<commit_before>//! Helpers to program the task state segment.
//! See Intel 3a, Chapter 7, Section 7

/// In 64-bit mode the TSS holds information that is not
/// directly related to the task-switch mechanism,
/// but is used for finding kernel level stack
/// if interrupts arrive while in kernel mode.
#[derive(Clone, Copy, Debug)]
#[repr(C, packed)]
pub struct TaskStateSegment {
    pub reserved: u32,
    /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2.
    pub rsp: [u64; 3],
    pub reserved2: u64,
    /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers.
    pub ist: [u64; 7],
    pub reserved3: u64,
    pub reserved4: u16,
    /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base.
    pub iomap_base: u16,
}

impl TaskStateSegment {
    pub const fn new() -> TaskStateSegment {
        TaskStateSegment {
            reserved: 0,
            rsp: [0; 3],
            reserved2: 0,
            ist: [0; 7],
            reserved3: 0,
            reserved4: 0,
            iomap_base: 0,
        }
    }
}
<commit_msg>Update doc.<commit_after>//! Helpers to program the task state segment.
//! See Intel 3a, Chapter 7, Section 7

/// Although hardware task-switching is not supported in 64-bit mode,
/// a 64-bit task state segment (TSS) must exist.
///
/// The TSS holds information important to 64-bit mode and that is not
/// directly related to the task-switch mechanism. This information includes:
///
/// # RSPn
/// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2.
/// RSPx is loaded in whenever an interrupt causes the CPU to change PL to x.
///
/// # ISTn
/// The full 64-bit canonical forms of the interrupt stack table (IST) pointers.
/// You can set an interrupt vector to use an IST entry in the Interrupt Descriptor
/// Table by giving it a number from 0 - 7. If 0 is selected, then the IST mechanism
/// is not used. If any other number is selected then when that interrupt vector is
/// called the CPU will load RSP from the corresponding IST entry. This is useful for
/// handling things like double faults, since you don't have to worry about switching
/// stacks; the CPU will do it for you.
///
/// # I/O map base address
/// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base.
///
/// The operating system must create at least one 64-bit TSS after activating IA-32e mode.
/// It must execute the LTR instruction (in 64-bit mode) to load the TR register with a
/// pointer to the 64-bit TSS responsible for both 64-bitmode programs and
/// compatibility-mode programs ([load_tr](crate::task::load_tr)).
#[derive(Clone, Copy, Debug)]
#[repr(C, packed)]
pub struct TaskStateSegment {
    pub reserved: u32,
    /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2.
    pub rsp: [u64; 3],
    pub reserved2: u64,
    /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers.
    pub ist: [u64; 7],
    pub reserved3: u64,
    pub reserved4: u16,
    /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base.
    pub iomap_base: u16,
}

impl TaskStateSegment {
    pub const fn new() -> TaskStateSegment {
        TaskStateSegment {
            reserved: 0,
            rsp: [0; 3],
            reserved2: 0,
            ist: [0; 7],
            reserved3: 0,
            reserved4: 0,
            iomap_base: 0,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
// Copyright 2016-2017 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Poisson distribution.

use rand::Rng;
use crate::{Distribution, Cauchy};
use crate::utils::log_gamma;

/// The Poisson distribution `Poisson(lambda)`.
///
/// This distribution has a density function:
/// `f(k) = lambda^k * exp(-lambda) / k!` for `k >= 0`.
///
/// # Example
///
/// ```
/// use rand_distr::{Poisson, Distribution};
///
/// let poi = Poisson::new(2.0).unwrap();
/// let v = poi.sample(&mut rand::thread_rng());
/// println!("{} is from a Poisson(2) distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Poisson {
    lambda: f64,
    // precalculated values
    exp_lambda: f64,
    log_lambda: f64,
    sqrt_2lambda: f64,
    magic_val: f64,
}

/// Error type returned from `Poisson::new`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Error {
    /// `lambda <= 0` or `nan`.
    ShapeTooSmall,
}

impl Poisson {
    /// Construct a new `Poisson` with the given shape parameter
    /// `lambda`.
    pub fn new(lambda: f64) -> Result<Poisson, Error> {
        if !(lambda > 0.0) {
            return Err(Error::ShapeTooSmall);
        }
        let log_lambda = lambda.ln();
        Ok(Poisson {
            lambda,
            exp_lambda: (-lambda).exp(),
            log_lambda,
            sqrt_2lambda: (2.0 * lambda).sqrt(),
            magic_val: lambda * log_lambda - log_gamma(1.0 + lambda),
        })
    }
}

impl Distribution<u64> for Poisson {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
        // using the algorithm from Numerical Recipes in C

        // for low expected values use the Knuth method
        if self.lambda < 12.0 {
            let mut result = 0;
            let mut p = 1.0;
            while p > self.exp_lambda {
                p *= rng.gen::<f64>();
                result += 1;
            }
            result - 1
        }
        // high expected values - rejection method
        else {
            let mut int_result: u64;

            // we use the Cauchy distribution as the comparison distribution
            // f(x) ~ 1/(1+x^2)
            let cauchy = Cauchy::new(0.0, 1.0).unwrap();

            loop {
                let mut result;
                let mut comp_dev;

                loop {
                    // draw from the Cauchy distribution
                    comp_dev = rng.sample(cauchy);
                    // shift the peak of the comparison ditribution
                    result = self.sqrt_2lambda * comp_dev + self.lambda;
                    // repeat the drawing until we are in the range of possible values
                    if result >= 0.0 {
                        break;
                    }
                }
                // now the result is a random variable greater than 0 with Cauchy distribution
                // the result should be an integer value
                result = result.floor();
                int_result = result as u64;

                // this is the ratio of the Poisson distribution to the comparison distribution
                // the magic value scales the distribution function to a range of approximately 0-1
                // since it is not exact, we multiply the ratio by 0.9 to avoid ratios greater than 1
                // this doesn't change the resulting distribution, only increases the rate of failed drawings
                let check = 0.9 * (1.0 + comp_dev * comp_dev)
                    * (result * self.log_lambda - log_gamma(1.0 + result) - self.magic_val).exp();

                // check with uniform random value - if below the threshold, we are within the target distribution
                if rng.gen::<f64>() <= check {
                    break;
                }
            }
            int_result
        }
    }
}

#[cfg(test)]
mod test {
    use crate::Distribution;
    use super::Poisson;

    #[test]
    fn test_poisson_10() {
        let poisson = Poisson::new(10.0).unwrap();
        let mut rng = crate::test::rng(123);
        let mut sum = 0;
        for _ in 0..1000 {
            sum += poisson.sample(&mut rng);
        }
        let avg = (sum as f64) / 1000.0;
        println!("Poisson average: {}", avg);
        assert!((avg - 10.0).abs() < 0.5); // not 100% certain, but probable enough
    }

    #[test]
    fn test_poisson_15() {
        // Take the 'high expected values' path
        let poisson = Poisson::new(15.0).unwrap();
        let mut rng = crate::test::rng(123);
        let mut sum = 0;
        for _ in 0..1000 {
            sum += poisson.sample(&mut rng);
        }
        let avg = (sum as f64) / 1000.0;
        println!("Poisson average: {}", avg);
        assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough
    }

    #[test]
    #[should_panic]
    fn test_poisson_invalid_lambda_zero() {
        Poisson::new(0.0).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_poisson_invalid_lambda_neg() {
        Poisson::new(-10.0).unwrap();
    }
}
<commit_msg>rand_distr: Check bounds before returning Poisson sample<commit_after>// Copyright 2018 Developers of the Rand project.
// Copyright 2016-2017 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Poisson distribution.

use rand::Rng;
use crate::{Distribution, Cauchy};
use crate::utils::log_gamma;

/// The Poisson distribution `Poisson(lambda)`.
///
/// This distribution has a density function:
/// `f(k) = lambda^k * exp(-lambda) / k!` for `k >= 0`.
///
/// # Example
///
/// ```
/// use rand_distr::{Poisson, Distribution};
///
/// let poi = Poisson::new(2.0).unwrap();
/// let v = poi.sample(&mut rand::thread_rng());
/// println!("{} is from a Poisson(2) distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Poisson {
    lambda: f64,
    // precalculated values
    exp_lambda: f64,
    log_lambda: f64,
    sqrt_2lambda: f64,
    magic_val: f64,
}

/// Error type returned from `Poisson::new`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Error {
    /// `lambda <= 0` or `nan`.
    ShapeTooSmall,
}

impl Poisson {
    /// Construct a new `Poisson` with the given shape parameter
    /// `lambda`.
    pub fn new(lambda: f64) -> Result<Poisson, Error> {
        if !(lambda > 0.0) {
            return Err(Error::ShapeTooSmall);
        }
        let log_lambda = lambda.ln();
        Ok(Poisson {
            lambda,
            exp_lambda: (-lambda).exp(),
            log_lambda,
            sqrt_2lambda: (2.0 * lambda).sqrt(),
            magic_val: lambda * log_lambda - log_gamma(1.0 + lambda),
        })
    }
}

impl Distribution<u64> for Poisson {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
        // using the algorithm from Numerical Recipes in C

        // for low expected values use the Knuth method
        if self.lambda < 12.0 {
            let mut result = 0;
            let mut p = 1.0;
            while p > self.exp_lambda {
                p *= rng.gen::<f64>();
                result += 1;
            }
            result - 1
        }
        // high expected values - rejection method
        else {
            let mut int_result: u64;

            // we use the Cauchy distribution as the comparison distribution
            // f(x) ~ 1/(1+x^2)
            let cauchy = Cauchy::new(0.0, 1.0).unwrap();

            loop {
                let mut result;
                let mut comp_dev;

                loop {
                    // draw from the Cauchy distribution
                    comp_dev = rng.sample(cauchy);
                    // shift the peak of the comparison ditribution
                    result = self.sqrt_2lambda * comp_dev + self.lambda;
                    // repeat the drawing until we are in the range of possible values
                    if result >= 0.0 {
                        break;
                    }
                }
                // now the result is a random variable greater than 0 with Cauchy distribution
                // the result should be an integer value
                result = result.floor();
                assert!(result >= 0.);
                assert!(result <= ::core::u64::MAX as f64);
                int_result = result as u64;

                // this is the ratio of the Poisson distribution to the comparison distribution
                // the magic value scales the distribution function to a range of approximately 0-1
                // since it is not exact, we multiply the ratio by 0.9 to avoid ratios greater than 1
                // this doesn't change the resulting distribution, only increases the rate of failed drawings
                let check = 0.9 * (1.0 + comp_dev * comp_dev)
                    * (result * self.log_lambda - log_gamma(1.0 + result) - self.magic_val).exp();

                // check with uniform random value - if below the threshold, we are within the target distribution
                if rng.gen::<f64>() <= check {
                    break;
                }
            }
            int_result
        }
    }
}

#[cfg(test)]
mod test {
    use crate::Distribution;
    use super::Poisson;

    #[test]
    fn test_poisson_10() {
        let poisson = Poisson::new(10.0).unwrap();
        let mut rng = crate::test::rng(123);
        let mut sum = 0;
        for _ in 0..1000 {
            sum += poisson.sample(&mut rng);
        }
        let avg = (sum as f64) / 1000.0;
        println!("Poisson average: {}", avg);
        assert!((avg - 10.0).abs() < 0.5); // not 100% certain, but probable enough
    }

    #[test]
    fn test_poisson_15() {
        // Take the 'high expected values' path
        let poisson = Poisson::new(15.0).unwrap();
        let mut rng = crate::test::rng(123);
        let mut sum = 0;
        for _ in 0..1000 {
            sum += poisson.sample(&mut rng);
        }
        let avg = (sum as f64) / 1000.0;
        println!("Poisson average: {}", avg);
        assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough
    }

    #[test]
    #[should_panic]
    fn test_poisson_invalid_lambda_zero() {
        Poisson::new(0.0).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_poisson_invalid_lambda_neg() {
        Poisson::new(-10.0).unwrap();
    }
}
<|endoftext|>


<commit_before>//! JIT Compiler to generate code fragments in runtime.

#![feature(libc)]
extern crate libc;
extern crate llvm;

extern crate common;

use std::borrow::Borrow;
use std::marker::PhantomData;

use llvm::*;

use common::err::{Void, void_ok};

pub const JIT_OPT_LVEL: usize = 2;

pub struct JitCompiler<'a>
{
  ctx   : Option<CBox<Context>>,
  module: Option<CSemiBox<'a, Module>>,
  ee    : Option<JitEngine<'a>>,

  _marker: PhantomData<&'a ()>
}

impl<'a> JitCompiler<'a>
{
  pub fn new() -> JitCompiler<'a>
  {
    JitCompiler {
      ctx    : Some(Context::new()),
      module : None,
      ee     : None,

      _marker: PhantomData
    }
  }

  pub fn init_module(&'a mut self) -> Void
  {
    self.module = Some(Module::new("xxx", self.ctx.as_ref().unwrap()));
    self.ee     = Some(JitEngine::new((self.module.as_ref()).unwrap(), JitOptions {opt_level: JIT_OPT_LVEL}).unwrap());

    void_ok
  }

  pub fn load_from_bitcode(&'a mut self, path: &str) -> Void
  {
    self.module = Some(Module::parse_bitcode(self.ctx.as_ref().unwrap(), path)
      .expect(&format!("loading {} failed...", path)));
    self.ee     = Some(JitEngine::new((self.module.as_ref()).unwrap(), JitOptions {opt_level: JIT_OPT_LVEL}).unwrap());

    void_ok
  }
}

pub struct JitEngineBuilder<'a>
{
  ctx: &'a Context
}

impl<'a> JitEngineBuilder<'a>
{
  pub fn new(ctx: &'a Context) -> JitEngineBuilder<'a>
  {
    JitEngineBuilder {
      ctx: ctx
    }
  }

  pub fn new_module(&'a self, name: &str) -> ModuleBuilder<'a>
  {
    ModuleBuilder {
      ctx: self.ctx,
      module: Module::new(name, self.ctx)
    }
  }

  pub fn from_bitcode(&'a mut self, path: &str) -> ModuleBuilder<'a>
  {
    ModuleBuilder {
      ctx: self.ctx,
      module: Module::parse_bitcode(self.ctx, path)
                .expect(&format!("loading bitcode at '{}' failed...", path))
    }
  }

  pub fn from_ir(&'a mut self, path: &str) -> ModuleBuilder<'a>
  {
    ModuleBuilder {
      ctx: self.ctx,
      module: Module::parse_ir(self.ctx, path)
                .expect(&format!("loading IR at '{}' failed...", path))
    }
  }
}

pub struct ModuleBuilder<'a>
{
  ctx: &'a Context,
  module: CSemiBox<'a, Module>
}

impl<'a> ModuleBuilder<'a>
{
  pub fn build(mut self, opt: JitOptions) -> EngineBuilder<'a> {
    EngineBuilder {
      ctx: self.ctx,
      module: self.module,
      engine: None
    }
  }
}

pub struct EngineBuilder<'a>
{
  ctx: &'a Context,
  module: CSemiBox<'a, Module>,
  engine: Option<JitEngine<'a>>
}

impl<'a> EngineBuilder<'a>
{
  pub fn build(&'a mut self, opt: JitOptions) {
    self.engine = JitEngine::new(&self.module, opt).ok();
  }
}
<commit_msg>Implemented JitCompiler builder.<commit_after>//! JIT Compiler to generate code fragments in runtime.

#![feature(libc)]
extern crate libc;
extern crate llvm;

extern crate common;

use std::borrow::Borrow;
use std::marker::PhantomData;

use llvm::*;

use common::err::{Void, void_ok};

pub const JIT_OPT_LVEL: usize = 2;

pub struct JitEngineBuilder<'a>
{
  ctx: &'a Context
}

impl<'a> JitEngineBuilder<'a>
{
  pub fn new(ctx: &'a Context) -> JitEngineBuilder<'a>
  {
    JitEngineBuilder {
      ctx: ctx
    }
  }

  pub fn new_module(&'a self, name: &str) -> ModuleBuilder<'a>
  {
    ModuleBuilder {
      ctx: self.ctx,
      module: Module::new(name, self.ctx)
    }
  }

  pub fn from_bitcode(&'a mut self, path: &str) -> ModuleBuilder<'a>
  {
    ModuleBuilder {
      ctx: self.ctx,
      module: Module::parse_bitcode(self.ctx, path)
                .expect(&format!("loading bitcode at '{}' failed...", path))
    }
  }

  pub fn from_ir(&'a mut self, path: &str) -> ModuleBuilder<'a>
  {
    ModuleBuilder {
      ctx: self.ctx,
      module: Module::parse_ir(self.ctx, path)
                .expect(&format!("loading IR at '{}' failed...", path))
    }
  }
}

pub struct ModuleBuilder<'a>
{
  ctx: &'a Context,
  module: CSemiBox<'a, Module>
}

impl<'a> ModuleBuilder<'a>
{
  pub fn build(mut self, opt: JitOptions) -> EngineBuilder<'a> {
    EngineBuilder {
      ctx: self.ctx,
      module: self.module,
      engine: None
    }
  }
}

pub struct EngineBuilder<'a>
{
  ctx: &'a Context,
  module: CSemiBox<'a, Module>,
  engine: Option<JitEngine<'a>>
}

impl<'a> EngineBuilder<'a>
{
  pub fn set_jit(&'a mut self, opt: JitOptions) -> Void {
    self.engine = JitEngine::new(&self.module, opt).ok();

    void_ok
  }

  pub fn build(mut self) -> JitCompiler<'a>
  {
    JitCompiler {
      ctx: self.ctx,
      module: self.module,
      engine: self.engine.unwrap()
    }
  }
}

pub struct JitCompiler<'a>
{
  ctx: &'a Context,
  module: CSemiBox<'a, Module>,
  engine: JitEngine<'a>
}
<|endoftext|>


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

use io::{self, Error, ErrorKind};
use libc::{self, c_int, gid_t, pid_t, uid_t};
use ptr;

use sys::cvt;
use sys::process::process_common::*;

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

impl Command {
    pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
                 -> io::Result<(Process, StdioPipes)> {
        use sys;

        const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";

        let envp = self.capture_env();

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

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

        if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? {
            return Ok((ret, ours))
        }

        let (input, output) = sys::pipe::anon_pipe()?;

        let pid = unsafe {
            match cvt(libc::fork())? {
                0 => {
                    drop(input);
                    let err = self.do_exec(theirs, envp.as_ref());
                    let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32;
                    let bytes = [
                        (errno >> 24) as u8,
                        (errno >> 16) as u8,
                        (errno >>  8) as u8,
                        (errno >>  0) as u8,
                        CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1],
                        CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3]
                    ];
                    // pipe I/O up to PIPE_BUF bytes should be atomic, and then
                    // we want to be sure we *don't* run at_exit destructors as
                    // we're being torn down regardless
                    assert!(output.write(&bytes).is_ok());
                    libc::_exit(1)
                }
                n => n,
            }
        };

        let mut p = Process { pid: pid, status: None };
        drop(output);
        let mut bytes = [0; 8];

        // loop to handle EINTR
        loop {
            match input.read(&mut bytes) {
                Ok(0) => return Ok((p, ours)),
                Ok(8) => {
                    assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]),
                            "Validation on the CLOEXEC pipe failed: {:?}", bytes);
                    let errno = combine(&bytes[0.. 4]);
                    assert!(p.wait().is_ok(),
                            "wait() should either return Ok or panic");
                    return Err(Error::from_raw_os_error(errno))
                }
                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
                Err(e) => {
                    assert!(p.wait().is_ok(),
                            "wait() should either return Ok or panic");
                    panic!("the CLOEXEC pipe failed: {:?}", e)
                },
                Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic
                    assert!(p.wait().is_ok(),
                            "wait() should either return Ok or panic");
                    panic!("short read on the CLOEXEC pipe")
                }
            }
        }

        fn combine(arr: &[u8]) -> i32 {
            let a = arr[0] as u32;
            let b = arr[1] as u32;
            let c = arr[2] as u32;
            let d = arr[3] as u32;

            ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32
        }
    }

    pub fn exec(&mut self, default: Stdio) -> io::Error {
        let envp = self.capture_env();

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

        match self.setup_io(default, true) {
            Ok((_, theirs)) => unsafe { self.do_exec(theirs, envp.as_ref()) },
            Err(e) => e,
        }
    }

    // And at this point we've reached a special time in the life of the
    // child. The child must now be considered hamstrung and unable to
    // do anything other than syscalls really. Consider the following
    // scenario:
    //
    //      1. Thread A of process 1 grabs the malloc() mutex
    //      2. Thread B of process 1 forks(), creating thread C
    //      3. Thread C of process 2 then attempts to malloc()
    //      4. The memory of process 2 is the same as the memory of
    //         process 1, so the mutex is locked.
    //
    // This situation looks a lot like deadlock, right? It turns out
    // that this is what pthread_atfork() takes care of, which is
    // presumably implemented across platforms. The first thing that
    // threads to *before* forking is to do things like grab the malloc
    // mutex, and then after the fork they unlock it.
    //
    // Despite this information, libnative's spawn has been witnessed to
    // deadlock on both macOS and FreeBSD. I'm not entirely sure why, but
    // all collected backtraces point at malloc/free traffic in the
    // child spawned process.
    //
    // For this reason, the block of code below should contain 0
    // invocations of either malloc of free (or their related friends).
    //
    // As an example of not having malloc/free traffic, we don't close
    // this file descriptor by dropping the FileDesc (which contains an
    // allocation). Instead we just close it manually. This will never
    // have the drop glue anyway because this code never returns (the
    // child will either exec() or invoke libc::exit)
    unsafe fn do_exec(
        &mut self,
        stdio: ChildPipes,
        maybe_envp: Option<&CStringArray>
    ) -> io::Error {
        use sys::{self, cvt_r};

        macro_rules! t {
            ($e:expr) => (match $e {
                Ok(e) => e,
                Err(e) => return e,
            })
        }

        if let Some(fd) = stdio.stdin.fd() {
            t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO)));
        }
        if let Some(fd) = stdio.stdout.fd() {
            t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO)));
        }
        if let Some(fd) = stdio.stderr.fd() {
            t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO)));
        }

        if cfg!(not(any(target_os = "l4re"))) {
            if let Some(u) = self.get_gid() {
                t!(cvt(libc::setgid(u as gid_t)));
            }
            if let Some(u) = self.get_uid() {
                // When dropping privileges from root, the `setgroups` call
                // will remove any extraneous groups. If we don't call this,
                // then even though our uid has dropped, we may still have
                // groups that enable us to do super-user things. This will
                // fail if we aren't root, so don't bother checking the
                // return value, this is just done as an optimistic
                // privilege dropping function.
                let _ = libc::setgroups(0, ptr::null());

                t!(cvt(libc::setuid(u as uid_t)));
            }
        }
        if let Some(ref cwd) = *self.get_cwd() {
            t!(cvt(libc::chdir(cwd.as_ptr())));
        }
        if let Some(envp) = maybe_envp {
            *sys::os::environ() = envp.as_ptr();
        }

        // emscripten has no signal support.
        #[cfg(not(any(target_os = "emscripten")))]
        {
            use mem;
            // Reset signal handling so the child process starts in a
            // standardized state. libstd ignores SIGPIPE, and signal-handling
            // libraries often set a mask. Child processes inherit ignored
            // signals and the signal mask from their parent, but most
            // UNIX programs do not reset these things on their own, so we
            // need to clean things up now to avoid confusing the program
            // we're about to run.
            let mut set: libc::sigset_t = mem::uninitialized();
            if cfg!(target_os = "android") {
                // Implementing sigemptyset allow us to support older Android
                // versions. See the comment about Android and sig* functions in
                // process_common.rs
                libc::memset(&mut set as *mut _ as *mut _,
                             0,
                             mem::size_of::<libc::sigset_t>());
            } else {
                t!(cvt(libc::sigemptyset(&mut set)));
            }
            t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set,
                                         ptr::null_mut())));
            let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL);
            if ret == libc::SIG_ERR {
                return io::Error::last_os_error()
            }
        }

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

        libc::execvp(self.get_argv()[0], self.get_argv().as_ptr());
        io::Error::last_os_error()
    }

    #[cfg(not(any(target_os = "macos", target_os = "freebsd")))]
    fn posix_spawn(&mut self, _stdio: &ChildPipes, _envp: Option<&CStringArray>)
        -> io::Result<Option<Process>>
    {
        Ok(None)
    }

    #[cfg(any(target_os = "macos", target_os = "freebsd"))]
    fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>)
        -> io::Result<Option<Process>>
    {
        use mem;
        use sys;

        if self.get_cwd().is_some() ||
            self.get_gid().is_some() ||
            self.get_uid().is_some() ||
            self.get_closures().len() != 0 {
            return Ok(None)
        }

        let mut p = Process { pid: 0, status: None };

        struct PosixSpawnFileActions(libc::posix_spawn_file_actions_t);

        impl Drop for PosixSpawnFileActions {
            fn drop(&mut self) {
                unsafe {
                    libc::posix_spawn_file_actions_destroy(&mut self.0);
                }
            }
        }

        struct PosixSpawnattr(libc::posix_spawnattr_t);

        impl Drop for PosixSpawnattr {
            fn drop(&mut self) {
                unsafe {
                    libc::posix_spawnattr_destroy(&mut self.0);
                }
            }
        }

        unsafe {
            let mut file_actions = PosixSpawnFileActions(mem::uninitialized());
            let mut attrs = PosixSpawnattr(mem::uninitialized());

            libc::posix_spawnattr_init(&mut attrs.0);
            libc::posix_spawn_file_actions_init(&mut file_actions.0);

            if let Some(fd) = stdio.stdin.fd() {
                cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
                                                           fd,
                                                           libc::STDIN_FILENO))?;
            }
            if let Some(fd) = stdio.stdout.fd() {
                cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
                                                           fd,
                                                           libc::STDOUT_FILENO))?;
            }
            if let Some(fd) = stdio.stderr.fd() {
                cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
                                                           fd,
                                                           libc::STDERR_FILENO))?;
            }

            let mut set: libc::sigset_t = mem::uninitialized();
            cvt(libc::sigemptyset(&mut set))?;
            cvt(libc::posix_spawnattr_setsigmask(&mut attrs.0,
                                                 &set))?;
            cvt(libc::sigaddset(&mut set, libc::SIGPIPE))?;
            cvt(libc::posix_spawnattr_setsigdefault(&mut attrs.0,
                                                    &set))?;

            let flags = libc::POSIX_SPAWN_SETSIGDEF |
                libc::POSIX_SPAWN_SETSIGMASK;
            cvt(libc::posix_spawnattr_setflags(&mut attrs.0, flags as _))?;

            let envp = envp.map(|c| c.as_ptr())
                .unwrap_or(*sys::os::environ() as *const _);
            let ret = libc::posix_spawnp(
                &mut p.pid,
                self.get_argv()[0],
                &file_actions.0,
                &attrs.0,
                self.get_argv().as_ptr() as *const _,
                envp as *const _,
            );
            if ret == 0 {
                Ok(Some(p))
            } else {
                Err(io::Error::from_raw_os_error(ret))
            }
        }
    }
}

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

/// The unique id of the process (this should never be negative).
pub struct Process {
    pid: pid_t,
    status: Option<ExitStatus>,
}

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

    pub fn kill(&mut self) -> io::Result<()> {
        // If we've already waited on this process then the pid can be recycled
        // and used for another process, and we probably shouldn't be killing
        // random processes, so just return an error.
        if self.status.is_some() {
            Err(Error::new(ErrorKind::InvalidInput,
                           "invalid argument: can't kill an exited process"))
        } else {
            cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ())
        }
    }

    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        use sys::cvt_r;
        if let Some(status) = self.status {
            return Ok(status)
        }
        let mut status = 0 as c_int;
        cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
        self.status = Some(ExitStatus::new(status));
        Ok(ExitStatus::new(status))
    }

    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        if let Some(status) = self.status {
            return Ok(Some(status))
        }
        let mut status = 0 as c_int;
        let pid = cvt(unsafe {
            libc::waitpid(self.pid, &mut status, libc::WNOHANG)
        })?;
        if pid == 0 {
            Ok(None)
        } else {
            self.status = Some(ExitStatus::new(status));
            Ok(Some(ExitStatus::new(status)))
        }
    }
}
<commit_msg>Add comment explaining when posix_spawn() can be supported.<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use io::{self, Error, ErrorKind};
use libc::{self, c_int, gid_t, pid_t, uid_t};
use ptr;

use sys::cvt;
use sys::process::process_common::*;

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

impl Command {
    pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
                 -> io::Result<(Process, StdioPipes)> {
        use sys;

        const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";

        let envp = self.capture_env();

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

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

        if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? {
            return Ok((ret, ours))
        }

        let (input, output) = sys::pipe::anon_pipe()?;

        let pid = unsafe {
            match cvt(libc::fork())? {
                0 => {
                    drop(input);
                    let err = self.do_exec(theirs, envp.as_ref());
                    let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32;
                    let bytes = [
                        (errno >> 24) as u8,
                        (errno >> 16) as u8,
                        (errno >>  8) as u8,
                        (errno >>  0) as u8,
                        CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1],
                        CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3]
                    ];
                    // pipe I/O up to PIPE_BUF bytes should be atomic, and then
                    // we want to be sure we *don't* run at_exit destructors as
                    // we're being torn down regardless
                    assert!(output.write(&bytes).is_ok());
                    libc::_exit(1)
                }
                n => n,
            }
        };

        let mut p = Process { pid: pid, status: None };
        drop(output);
        let mut bytes = [0; 8];

        // loop to handle EINTR
        loop {
            match input.read(&mut bytes) {
                Ok(0) => return Ok((p, ours)),
                Ok(8) => {
                    assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]),
                            "Validation on the CLOEXEC pipe failed: {:?}", bytes);
                    let errno = combine(&bytes[0.. 4]);
                    assert!(p.wait().is_ok(),
                            "wait() should either return Ok or panic");
                    return Err(Error::from_raw_os_error(errno))
                }
                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
                Err(e) => {
                    assert!(p.wait().is_ok(),
                            "wait() should either return Ok or panic");
                    panic!("the CLOEXEC pipe failed: {:?}", e)
                },
                Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic
                    assert!(p.wait().is_ok(),
                            "wait() should either return Ok or panic");
                    panic!("short read on the CLOEXEC pipe")
                }
            }
        }

        fn combine(arr: &[u8]) -> i32 {
            let a = arr[0] as u32;
            let b = arr[1] as u32;
            let c = arr[2] as u32;
            let d = arr[3] as u32;

            ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32
        }
    }

    pub fn exec(&mut self, default: Stdio) -> io::Error {
        let envp = self.capture_env();

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

        match self.setup_io(default, true) {
            Ok((_, theirs)) => unsafe { self.do_exec(theirs, envp.as_ref()) },
            Err(e) => e,
        }
    }

    // And at this point we've reached a special time in the life of the
    // child. The child must now be considered hamstrung and unable to
    // do anything other than syscalls really. Consider the following
    // scenario:
    //
    //      1. Thread A of process 1 grabs the malloc() mutex
    //      2. Thread B of process 1 forks(), creating thread C
    //      3. Thread C of process 2 then attempts to malloc()
    //      4. The memory of process 2 is the same as the memory of
    //         process 1, so the mutex is locked.
    //
    // This situation looks a lot like deadlock, right? It turns out
    // that this is what pthread_atfork() takes care of, which is
    // presumably implemented across platforms. The first thing that
    // threads to *before* forking is to do things like grab the malloc
    // mutex, and then after the fork they unlock it.
    //
    // Despite this information, libnative's spawn has been witnessed to
    // deadlock on both macOS and FreeBSD. I'm not entirely sure why, but
    // all collected backtraces point at malloc/free traffic in the
    // child spawned process.
    //
    // For this reason, the block of code below should contain 0
    // invocations of either malloc of free (or their related friends).
    //
    // As an example of not having malloc/free traffic, we don't close
    // this file descriptor by dropping the FileDesc (which contains an
    // allocation). Instead we just close it manually. This will never
    // have the drop glue anyway because this code never returns (the
    // child will either exec() or invoke libc::exit)
    unsafe fn do_exec(
        &mut self,
        stdio: ChildPipes,
        maybe_envp: Option<&CStringArray>
    ) -> io::Error {
        use sys::{self, cvt_r};

        macro_rules! t {
            ($e:expr) => (match $e {
                Ok(e) => e,
                Err(e) => return e,
            })
        }

        if let Some(fd) = stdio.stdin.fd() {
            t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO)));
        }
        if let Some(fd) = stdio.stdout.fd() {
            t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO)));
        }
        if let Some(fd) = stdio.stderr.fd() {
            t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO)));
        }

        if cfg!(not(any(target_os = "l4re"))) {
            if let Some(u) = self.get_gid() {
                t!(cvt(libc::setgid(u as gid_t)));
            }
            if let Some(u) = self.get_uid() {
                // When dropping privileges from root, the `setgroups` call
                // will remove any extraneous groups. If we don't call this,
                // then even though our uid has dropped, we may still have
                // groups that enable us to do super-user things. This will
                // fail if we aren't root, so don't bother checking the
                // return value, this is just done as an optimistic
                // privilege dropping function.
                let _ = libc::setgroups(0, ptr::null());

                t!(cvt(libc::setuid(u as uid_t)));
            }
        }
        if let Some(ref cwd) = *self.get_cwd() {
            t!(cvt(libc::chdir(cwd.as_ptr())));
        }
        if let Some(envp) = maybe_envp {
            *sys::os::environ() = envp.as_ptr();
        }

        // emscripten has no signal support.
        #[cfg(not(any(target_os = "emscripten")))]
        {
            use mem;
            // Reset signal handling so the child process starts in a
            // standardized state. libstd ignores SIGPIPE, and signal-handling
            // libraries often set a mask. Child processes inherit ignored
            // signals and the signal mask from their parent, but most
            // UNIX programs do not reset these things on their own, so we
            // need to clean things up now to avoid confusing the program
            // we're about to run.
            let mut set: libc::sigset_t = mem::uninitialized();
            if cfg!(target_os = "android") {
                // Implementing sigemptyset allow us to support older Android
                // versions. See the comment about Android and sig* functions in
                // process_common.rs
                libc::memset(&mut set as *mut _ as *mut _,
                             0,
                             mem::size_of::<libc::sigset_t>());
            } else {
                t!(cvt(libc::sigemptyset(&mut set)));
            }
            t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set,
                                         ptr::null_mut())));
            let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL);
            if ret == libc::SIG_ERR {
                return io::Error::last_os_error()
            }
        }

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

        libc::execvp(self.get_argv()[0], self.get_argv().as_ptr());
        io::Error::last_os_error()
    }

    #[cfg(not(any(target_os = "macos", target_os = "freebsd")))]
    fn posix_spawn(&mut self, _stdio: &ChildPipes, _envp: Option<&CStringArray>)
        -> io::Result<Option<Process>>
    {
        Ok(None)
    }

    // Only support platforms for which posix_spawn() can return ENOENT
    // directly.
    #[cfg(any(target_os = "macos", target_os = "freebsd"))]
    fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>)
        -> io::Result<Option<Process>>
    {
        use mem;
        use sys;

        if self.get_cwd().is_some() ||
            self.get_gid().is_some() ||
            self.get_uid().is_some() ||
            self.get_closures().len() != 0 {
            return Ok(None)
        }

        let mut p = Process { pid: 0, status: None };

        struct PosixSpawnFileActions(libc::posix_spawn_file_actions_t);

        impl Drop for PosixSpawnFileActions {
            fn drop(&mut self) {
                unsafe {
                    libc::posix_spawn_file_actions_destroy(&mut self.0);
                }
            }
        }

        struct PosixSpawnattr(libc::posix_spawnattr_t);

        impl Drop for PosixSpawnattr {
            fn drop(&mut self) {
                unsafe {
                    libc::posix_spawnattr_destroy(&mut self.0);
                }
            }
        }

        unsafe {
            let mut file_actions = PosixSpawnFileActions(mem::uninitialized());
            let mut attrs = PosixSpawnattr(mem::uninitialized());

            libc::posix_spawnattr_init(&mut attrs.0);
            libc::posix_spawn_file_actions_init(&mut file_actions.0);

            if let Some(fd) = stdio.stdin.fd() {
                cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
                                                           fd,
                                                           libc::STDIN_FILENO))?;
            }
            if let Some(fd) = stdio.stdout.fd() {
                cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
                                                           fd,
                                                           libc::STDOUT_FILENO))?;
            }
            if let Some(fd) = stdio.stderr.fd() {
                cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
                                                           fd,
                                                           libc::STDERR_FILENO))?;
            }

            let mut set: libc::sigset_t = mem::uninitialized();
            cvt(libc::sigemptyset(&mut set))?;
            cvt(libc::posix_spawnattr_setsigmask(&mut attrs.0,
                                                 &set))?;
            cvt(libc::sigaddset(&mut set, libc::SIGPIPE))?;
            cvt(libc::posix_spawnattr_setsigdefault(&mut attrs.0,
                                                    &set))?;

            let flags = libc::POSIX_SPAWN_SETSIGDEF |
                libc::POSIX_SPAWN_SETSIGMASK;
            cvt(libc::posix_spawnattr_setflags(&mut attrs.0, flags as _))?;

            let envp = envp.map(|c| c.as_ptr())
                .unwrap_or(*sys::os::environ() as *const _);
            let ret = libc::posix_spawnp(
                &mut p.pid,
                self.get_argv()[0],
                &file_actions.0,
                &attrs.0,
                self.get_argv().as_ptr() as *const _,
                envp as *const _,
            );
            if ret == 0 {
                Ok(Some(p))
            } else {
                Err(io::Error::from_raw_os_error(ret))
            }
        }
    }
}

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

/// The unique id of the process (this should never be negative).
pub struct Process {
    pid: pid_t,
    status: Option<ExitStatus>,
}

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

    pub fn kill(&mut self) -> io::Result<()> {
        // If we've already waited on this process then the pid can be recycled
        // and used for another process, and we probably shouldn't be killing
        // random processes, so just return an error.
        if self.status.is_some() {
            Err(Error::new(ErrorKind::InvalidInput,
                           "invalid argument: can't kill an exited process"))
        } else {
            cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ())
        }
    }

    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        use sys::cvt_r;
        if let Some(status) = self.status {
            return Ok(status)
        }
        let mut status = 0 as c_int;
        cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
        self.status = Some(ExitStatus::new(status));
        Ok(ExitStatus::new(status))
    }

    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        if let Some(status) = self.status {
            return Ok(Some(status))
        }
        let mut status = 0 as c_int;
        let pid = cvt(unsafe {
            libc::waitpid(self.pid, &mut status, libc::WNOHANG)
        })?;
        if pid == 0 {
            Ok(None)
        } else {
            self.status = Some(ExitStatus::new(status));
            Ok(Some(ExitStatus::new(status)))
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use serde_json::{json, Value};

use super::{CreateAllowedMentions, CreateEmbed};
use crate::builder::CreateComponents;
use crate::{
    model::interactions::{
        InteractionApplicationCommandCallbackDataFlags,
        InteractionResponseType,
    },
    utils,
};

#[derive(Clone, Debug)]
pub struct CreateInteractionResponse(pub HashMap<&'static str, Value>);

impl CreateInteractionResponse {
    /// Sets the InteractionResponseType of the message.
    ///
    /// Defaults to `ChannelMessageWithSource`.
    pub fn kind(&mut self, kind: InteractionResponseType) -> &mut Self {
        self.0.insert("type", Value::Number(serde_json::Number::from(kind as u8)));
        self
    }

    /// Sets the `InteractionApplicationCommandCallbackData` for the message.
    pub fn interaction_response_data<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateInteractionResponseData) -> &mut CreateInteractionResponseData,
    {
        let mut data = CreateInteractionResponseData::default();
        f(&mut data);
        let map = utils::hashmap_to_json_map(data.0);
        let data = Value::Object(map);

        self.0.insert("data", data);
        self
    }
}

impl<'a> Default for CreateInteractionResponse {
    fn default() -> CreateInteractionResponse {
        let mut map = HashMap::new();
        map.insert("type", Value::Number(serde_json::Number::from(4)));

        CreateInteractionResponse(map)
    }
}

#[derive(Clone, Debug, Default)]
pub struct CreateInteractionResponseData(pub HashMap<&'static str, Value>);

impl CreateInteractionResponseData {
    /// Set whether the message is text-to-speech.
    ///
    /// Think carefully before setting this to `true`.
    ///
    /// Defaults to `false`.
    pub fn tts(&mut self, tts: bool) -> &mut Self {
        self.0.insert("tts", Value::Bool(tts));
        self
    }

    /// Set the content of the message.
    ///
    /// **Note**: Message contents must be under 2000 unicode code points.
    #[inline]
    pub fn content<D: ToString>(&mut self, content: D) -> &mut Self {
        self._content(content.to_string())
    }

    fn _content(&mut self, content: String) -> &mut Self {
        self.0.insert("content", Value::String(content));
        self
    }

    /// Create an embed for the message.
    pub fn embed<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateEmbed) -> &mut CreateEmbed,
    {
        let mut embed = CreateEmbed::default();
        f(&mut embed);
        self.add_embed(embed)
    }

    /// Adds an embed to the message.
    pub fn add_embed(&mut self, embed: CreateEmbed) -> &mut Self {
        let map = utils::hashmap_to_json_map(embed.0);
        let embed = Value::Object(map);

        let embeds = self.0.entry("embeds").or_insert_with(|| Value::Array(vec![]));

        if let Some(embeds) = embeds.as_array_mut() {
            embeds.push(embed);
        }

        self
    }

    /// Adds multiple embeds for the message.
    pub fn add_embeds(&mut self, embeds: Vec<CreateEmbed>) -> &mut Self {
        for embed in embeds {
            self.add_embed(embed);
        }

        self
    }

    /// Sets a single embed to include in the message
    ///
    /// Calling this will overwrite the embed list.
    /// To append embeds, call [`Self::add_embed`] instead.
    pub fn set_embed(&mut self, embed: CreateEmbed) -> &mut Self {
        let map = utils::hashmap_to_json_map(embed.0);
        let embed = Value::Object(map);
        self.0.insert("embeds", Value::Array(vec![embed]));

        self
    }

    /// Sets a list of embeds to include in the message.
    ///
    /// Calling this multiple times will overwrite the embed list.
    /// To append embeds, call [`Self::add_embed`] instead.
    pub fn set_embeds(&mut self, embeds: impl IntoIterator<Item = CreateEmbed>) -> &mut Self {
        let embeds =
            embeds.into_iter().map(|embed| utils::hashmap_to_json_map(embed.0).into()).collect();

        self.0.insert("embeds", Value::Array(embeds));
        self
    }

    /// Set the allowed mentions for the message.
    pub fn allowed_mentions<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateAllowedMentions) -> &mut CreateAllowedMentions,
    {
        let mut allowed_mentions = CreateAllowedMentions::default();
        f(&mut allowed_mentions);
        let map = utils::hashmap_to_json_map(allowed_mentions.0);
        let allowed_mentions = Value::Object(map);

        self.0.insert("allowed_mentions", allowed_mentions);
        self
    }

    /// Sets the flags for the message.
    pub fn flags(&mut self, flags: InteractionApplicationCommandCallbackDataFlags) -> &mut Self {
        self.0.insert("flags", Value::Number(serde_json::Number::from(flags.bits())));
        self
    }

    /// Creates components for this message.
    pub fn components<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateComponents) -> &mut CreateComponents,
    {
        let mut components = CreateComponents::default();
        f(&mut components);

        self.0.insert("components", Value::Array(components.0));
        self
    }

    /// Sets the components of this message.
    pub fn set_components(&mut self, components: CreateComponents) -> &mut Self {
        self.0.insert("components", Value::Array(components.0));
        self
    }

    /// Sets the custom id for modal interactions
    pub fn custom_id<D: ToString>(&mut self, id: D) -> &mut Self {
        self.0.insert("custom_id", Value::String(id.to_string()));
        self
    }

    /// Sets the titel for modal interactions
    pub fn title<D: ToString>(&mut self, title: D) -> &mut Self {
        self.0.insert("title", Value::String(title.to_string()));
        self
    }
}

#[derive(Clone, Debug)]
pub struct CreateAutocompleteResponse(pub HashMap<&'static str, Value>);

impl<'a> Default for CreateAutocompleteResponse {
    fn default() -> CreateAutocompleteResponse {
        let mut map = HashMap::new();
        map.insert("choices", Value::Array(vec![]));
        CreateAutocompleteResponse(map)
    }
}

impl CreateAutocompleteResponse {
    /// For autocomplete responses this sets their autocomplete suggestions.
    ///
    /// See the official docs on [`Application Command Option Choices`] for more information.
    ///
    /// [`Application Command Option Choices`]: https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-choice-structure
    pub fn set_choices(&mut self, choices: Value) -> &mut Self {
        self.0.insert("choices", choices);
        self
    }

    /// Add an int autocomplete choice.
    ///
    /// **Note**: There can be no more than 25 choices set. Name must be between 1 and 100 characters. Value must be between -2^53 and 2^53.
    pub fn add_int_choice<D: ToString>(&mut self, name: D, value: i64) -> &mut Self {
        let choice = json!({
            "name": name.to_string(),
            "value" : value
        });
        self.add_choice(choice)
    }

    /// Adds a string autocomplete choice.
    ///
    /// **Note**: There can be no more than 25 choices set. Name must be between 1 and 100 characters. Value must be up to 100 characters.
    pub fn add_string_choice<D: ToString, E: ToString>(&mut self, name: D, value: E) -> &mut Self {
        let choice = json!({
            "name": name.to_string(),
            "value": value.to_string()
        });
        self.add_choice(choice)
    }

    /// Adds a number autocomplete choice.
    ///
    /// **Note**: There can be no more than 25 choices set. Name must be between 1 and 100 characters. Value must be between -2^53 and 2^53.
    pub fn add_number_choice<D: ToString>(&mut self, name: D, value: f64) -> &mut Self {
        let choice = json!({
            "name": name.to_string(),
            "value" : value
        });
        self.add_choice(choice)
    }

    fn add_choice(&mut self, value: Value) -> &mut Self {
        let choices = self.0.entry("choices").or_insert_with(|| Value::Array(vec![]));
        let choices_arr = choices.as_array_mut().expect("Must be an array");
        choices_arr.push(value);

        self
    }
}
<commit_msg>Fix typo (`titel` -> `title`)<commit_after>use std::collections::HashMap;

use serde_json::{json, Value};

use super::{CreateAllowedMentions, CreateEmbed};
use crate::builder::CreateComponents;
use crate::{
    model::interactions::{
        InteractionApplicationCommandCallbackDataFlags,
        InteractionResponseType,
    },
    utils,
};

#[derive(Clone, Debug)]
pub struct CreateInteractionResponse(pub HashMap<&'static str, Value>);

impl CreateInteractionResponse {
    /// Sets the InteractionResponseType of the message.
    ///
    /// Defaults to `ChannelMessageWithSource`.
    pub fn kind(&mut self, kind: InteractionResponseType) -> &mut Self {
        self.0.insert("type", Value::Number(serde_json::Number::from(kind as u8)));
        self
    }

    /// Sets the `InteractionApplicationCommandCallbackData` for the message.
    pub fn interaction_response_data<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateInteractionResponseData) -> &mut CreateInteractionResponseData,
    {
        let mut data = CreateInteractionResponseData::default();
        f(&mut data);
        let map = utils::hashmap_to_json_map(data.0);
        let data = Value::Object(map);

        self.0.insert("data", data);
        self
    }
}

impl<'a> Default for CreateInteractionResponse {
    fn default() -> CreateInteractionResponse {
        let mut map = HashMap::new();
        map.insert("type", Value::Number(serde_json::Number::from(4)));

        CreateInteractionResponse(map)
    }
}

#[derive(Clone, Debug, Default)]
pub struct CreateInteractionResponseData(pub HashMap<&'static str, Value>);

impl CreateInteractionResponseData {
    /// Set whether the message is text-to-speech.
    ///
    /// Think carefully before setting this to `true`.
    ///
    /// Defaults to `false`.
    pub fn tts(&mut self, tts: bool) -> &mut Self {
        self.0.insert("tts", Value::Bool(tts));
        self
    }

    /// Set the content of the message.
    ///
    /// **Note**: Message contents must be under 2000 unicode code points.
    #[inline]
    pub fn content<D: ToString>(&mut self, content: D) -> &mut Self {
        self._content(content.to_string())
    }

    fn _content(&mut self, content: String) -> &mut Self {
        self.0.insert("content", Value::String(content));
        self
    }

    /// Create an embed for the message.
    pub fn embed<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateEmbed) -> &mut CreateEmbed,
    {
        let mut embed = CreateEmbed::default();
        f(&mut embed);
        self.add_embed(embed)
    }

    /// Adds an embed to the message.
    pub fn add_embed(&mut self, embed: CreateEmbed) -> &mut Self {
        let map = utils::hashmap_to_json_map(embed.0);
        let embed = Value::Object(map);

        let embeds = self.0.entry("embeds").or_insert_with(|| Value::Array(vec![]));

        if let Some(embeds) = embeds.as_array_mut() {
            embeds.push(embed);
        }

        self
    }

    /// Adds multiple embeds for the message.
    pub fn add_embeds(&mut self, embeds: Vec<CreateEmbed>) -> &mut Self {
        for embed in embeds {
            self.add_embed(embed);
        }

        self
    }

    /// Sets a single embed to include in the message
    ///
    /// Calling this will overwrite the embed list.
    /// To append embeds, call [`Self::add_embed`] instead.
    pub fn set_embed(&mut self, embed: CreateEmbed) -> &mut Self {
        let map = utils::hashmap_to_json_map(embed.0);
        let embed = Value::Object(map);
        self.0.insert("embeds", Value::Array(vec![embed]));

        self
    }

    /// Sets a list of embeds to include in the message.
    ///
    /// Calling this multiple times will overwrite the embed list.
    /// To append embeds, call [`Self::add_embed`] instead.
    pub fn set_embeds(&mut self, embeds: impl IntoIterator<Item = CreateEmbed>) -> &mut Self {
        let embeds =
            embeds.into_iter().map(|embed| utils::hashmap_to_json_map(embed.0).into()).collect();

        self.0.insert("embeds", Value::Array(embeds));
        self
    }

    /// Set the allowed mentions for the message.
    pub fn allowed_mentions<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateAllowedMentions) -> &mut CreateAllowedMentions,
    {
        let mut allowed_mentions = CreateAllowedMentions::default();
        f(&mut allowed_mentions);
        let map = utils::hashmap_to_json_map(allowed_mentions.0);
        let allowed_mentions = Value::Object(map);

        self.0.insert("allowed_mentions", allowed_mentions);
        self
    }

    /// Sets the flags for the message.
    pub fn flags(&mut self, flags: InteractionApplicationCommandCallbackDataFlags) -> &mut Self {
        self.0.insert("flags", Value::Number(serde_json::Number::from(flags.bits())));
        self
    }

    /// Creates components for this message.
    pub fn components<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateComponents) -> &mut CreateComponents,
    {
        let mut components = CreateComponents::default();
        f(&mut components);

        self.0.insert("components", Value::Array(components.0));
        self
    }

    /// Sets the components of this message.
    pub fn set_components(&mut self, components: CreateComponents) -> &mut Self {
        self.0.insert("components", Value::Array(components.0));
        self
    }

    /// Sets the custom id for modal interactions
    pub fn custom_id<D: ToString>(&mut self, id: D) -> &mut Self {
        self.0.insert("custom_id", Value::String(id.to_string()));
        self
    }

    /// Sets the title for modal interactions
    pub fn title<D: ToString>(&mut self, title: D) -> &mut Self {
        self.0.insert("title", Value::String(title.to_string()));
        self
    }
}

#[derive(Clone, Debug)]
pub struct CreateAutocompleteResponse(pub HashMap<&'static str, Value>);

impl<'a> Default for CreateAutocompleteResponse {
    fn default() -> CreateAutocompleteResponse {
        let mut map = HashMap::new();
        map.insert("choices", Value::Array(vec![]));
        CreateAutocompleteResponse(map)
    }
}

impl CreateAutocompleteResponse {
    /// For autocomplete responses this sets their autocomplete suggestions.
    ///
    /// See the official docs on [`Application Command Option Choices`] for more information.
    ///
    /// [`Application Command Option Choices`]: https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-choice-structure
    pub fn set_choices(&mut self, choices: Value) -> &mut Self {
        self.0.insert("choices", choices);
        self
    }

    /// Add an int autocomplete choice.
    ///
    /// **Note**: There can be no more than 25 choices set. Name must be between 1 and 100 characters. Value must be between -2^53 and 2^53.
    pub fn add_int_choice<D: ToString>(&mut self, name: D, value: i64) -> &mut Self {
        let choice = json!({
            "name": name.to_string(),
            "value" : value
        });
        self.add_choice(choice)
    }

    /// Adds a string autocomplete choice.
    ///
    /// **Note**: There can be no more than 25 choices set. Name must be between 1 and 100 characters. Value must be up to 100 characters.
    pub fn add_string_choice<D: ToString, E: ToString>(&mut self, name: D, value: E) -> &mut Self {
        let choice = json!({
            "name": name.to_string(),
            "value": value.to_string()
        });
        self.add_choice(choice)
    }

    /// Adds a number autocomplete choice.
    ///
    /// **Note**: There can be no more than 25 choices set. Name must be between 1 and 100 characters. Value must be between -2^53 and 2^53.
    pub fn add_number_choice<D: ToString>(&mut self, name: D, value: f64) -> &mut Self {
        let choice = json!({
            "name": name.to_string(),
            "value" : value
        });
        self.add_choice(choice)
    }

    fn add_choice(&mut self, value: Value) -> &mut Self {
        let choices = self.0.entry("choices").or_insert_with(|| Value::Array(vec![]));
        let choices_arr = choices.as_array_mut().expect("Must be an array");
        choices_arr.push(value);

        self
    }
}
<|endoftext|>


<commit_before>use plat::*;
use vspace::*;
use panic::*;
use ::config::BootConfig;
use ::core::fmt::Write;
use ::core::marker::PhantomData;
use ::core::default::Default;
use super::halt::halt;
use super::vspace::*;
extern crate multiboot;

struct EarlyBootState<'h, 'l> {
    high_window : &'h BootHighWindow<'h>,
    low_window : &'l BootLowWindow<'l>,
    mbi_magic: usize,
    mbi: *const usize,
}

struct PostEarlyBootState<'a> {
    plat: PlatInterfaceType,
    /* currently just PhantomData as don't have anything
     * to return with a lifetime */
    phantom: PhantomData<&'a usize>,
}

fn display_multiboot<'a>(plat: &mut PlatInterfaceType, mbi: &'a multiboot::Multiboot<'a>) {
    write!(plat, "Multiboot information:\n").unwrap();
    if let Some(low) = mbi.lower_memory_bound() {
        write!(plat,"\t{}kb of low memory\n", low).unwrap();
    }
    if let Some(high) = mbi.upper_memory_bound() {
        write!(plat,"\t{}mb of high memory\nn", high / 1024).unwrap();
    }
    if let Some(boot) = mbi.boot_device() {
        write!(plat,"\tBoot device {:?}\n", boot).unwrap();
    }
    if let Some(line) = mbi.command_line() {
        write!(plat,"\tCommand line \"{}\"\n", line).unwrap();
    }
    if let Some(modules) = mbi.modules() {
        write!(plat,"Multiboot modules:\n").unwrap();
        for m in modules {
            write!(plat,"\t{:?}\n", m).unwrap();
        }
    }
    if let Some(memory) = mbi.memory_regions() {
        write!(plat,"Memory regions:\n").unwrap();
        for m in memory {
            write!(plat,"\t{:?}\n", m).unwrap();
        }
    }
}

/* We create a wrapper struct because I don't know how else
 * to get the lifetime of the return value of callback function
 * to line up with the multiboot lifetime */
struct mbi_wrapper<'a> {
    mbi: Option<multiboot::Multiboot<'a>>,
    callback: &'a Fn(u64, usize) -> Option<&'a [u8]>,
}

/* Try and boot the system, potentially returning an error.
 * Since if we fail there is no way to display or do anything
 * with the error we do do not bother to have an error type
 * This is specifically the 'early' boot as it happens before
 * we switch to the final kernel address space
 */
fn try_early_boot_system<'h, 'l>(init: EarlyBootState<'h, 'l>) -> Result<PostEarlyBootState<'h>, PlatInterfaceType> {
    /* Initial the serial output of our platform first so that
     * we can get debugging output. */
    let mut plat = get_platform(&BootConfig);
    plat.init_serial();
    write!(plat, "R4: In early setup\n").unwrap();
    /* Initialize the panic function so we can see anything
     * really bad that happens */
    panic_set_plat(&mut plat);
    /* Now we can continue with the rest of init */
    if init.mbi_magic as u64 != multiboot::SIGNATURE_RAX {
        write!(plat,"Invalid multiboot signature!\nExpected {} got {} with pointer {:?}\n", multiboot::SIGNATURE_RAX, init.mbi_magic, init.mbi).unwrap();
        return Err(plat);
    }
    let mut mbi = mbi_wrapper{mbi: None, callback: &|p, s| unsafe {
        Some(init.low_window.make_slice(p as usize, s))
        }};
    unsafe {
        /* Thanks to the stupidy in this function interface of requiring
         * an unsafe function we cannot pass a lambda expression. Since
         * a lambda cannot be made unsafe and we have no other way of
         * passing our state we just transmute the lambda. Unfortunately
         * this removes all type checking on our function :( */
        mbi.mbi = match multiboot::Multiboot::new(init.mbi as multiboot::PAddr, mbi.callback) {
            Some(mbi) => Some(mbi),
            None => {
                write!(plat,"Failed to create multiboot!\n");
                return Err(plat)
                }
            };
        if let &Some(ref mbi) = &mbi.mbi {
            display_multiboot(&mut plat, &mbi);
        }
    }
    Ok(PostEarlyBootState{ plat: plat, phantom: PhantomData })
}

/* Represent the multiboot info pointer as a pointer to
 * a usize for the moment. This will allow us to get the
 * lifetimes correct, and we will fill in the correct
 * type later */
#[no_mangle]
pub extern fn boot_system(magic: usize, mbi: *const usize) {
    /* This *will* be our final kernel window, but it is not our window
     * yet. We create it here so that our temporary high kernel window,
     * which is a subset of the final kernel window, can be constructed
     * from it as having the same lifetime. This allows any references
     * created from the boot high kernel window being able to live on
     * into the final kernel window */
    let final_window = KernelWindow::default();
    /* this variable will hold our system state as returned by early boot */
    let mut boot;
    {
        /* Construct our system state for boot */
        let boot_high_window;
        unsafe {
            boot_high_window = final_window.subwindow(BootHighWindow::default());
        }
        /* whilst doing early boot we can also access things in low memory */
        let boot_low_window = BootLowWindow::default();
        let boot_state = EarlyBootState {
            high_window: &boot_high_window,
            low_window: &boot_low_window,
            mbi_magic: magic,
            mbi: mbi,
        };
        boot = match try_early_boot_system(boot_state) {
            Err(mut plat) => {
                    write!(plat, "Failed early init. hlt'ing\n").unwrap();
                    halt();
                },
            Ok(b) => b,
        };
        /* The 'plat' definition got moved into boot. Reset the panic location */
        panic_set_plat(&mut boot.plat);
    }
    unimplemented!()
}
<commit_msg>Squash warnings<commit_after>use plat::*;
use vspace::*;
use panic::*;
use ::config::BootConfig;
use ::core::fmt::Write;
use ::core::marker::PhantomData;
use ::core::default::Default;
use super::halt::halt;
use super::vspace::*;
extern crate multiboot;

struct EarlyBootState<'h, 'l> {
    high_window : &'h BootHighWindow<'h>,
    low_window : &'l BootLowWindow<'l>,
    mbi_magic: usize,
    mbi: *const usize,
}

struct PostEarlyBootState<'a> {
    plat: PlatInterfaceType,
    /* currently just PhantomData as don't have anything
     * to return with a lifetime */
    phantom: PhantomData<&'a usize>,
}

fn display_multiboot<'a>(plat: &mut PlatInterfaceType, mbi: &'a multiboot::Multiboot<'a>) {
    write!(plat, "Multiboot information:\n").unwrap();
    if let Some(low) = mbi.lower_memory_bound() {
        write!(plat,"\t{}kb of low memory\n", low).unwrap();
    }
    if let Some(high) = mbi.upper_memory_bound() {
        write!(plat,"\t{}mb of high memory\nn", high / 1024).unwrap();
    }
    if let Some(boot) = mbi.boot_device() {
        write!(plat,"\tBoot device {:?}\n", boot).unwrap();
    }
    if let Some(line) = mbi.command_line() {
        write!(plat,"\tCommand line \"{}\"\n", line).unwrap();
    }
    if let Some(modules) = mbi.modules() {
        write!(plat,"Multiboot modules:\n").unwrap();
        for m in modules {
            write!(plat,"\t{:?}\n", m).unwrap();
        }
    }
    if let Some(memory) = mbi.memory_regions() {
        write!(plat,"Memory regions:\n").unwrap();
        for m in memory {
            write!(plat,"\t{:?}\n", m).unwrap();
        }
    }
}

/* We create a wrapper struct because I don't know how else
 * to get the lifetime of the return value of callback function
 * to line up with the multiboot lifetime */
struct MbiWrapper<'a> {
    mbi: Option<multiboot::Multiboot<'a>>,
    callback: &'a Fn(u64, usize) -> Option<&'a [u8]>,
}

/* Try and boot the system, potentially returning an error.
 * Since if we fail there is no way to display or do anything
 * with the error we do do not bother to have an error type
 * This is specifically the 'early' boot as it happens before
 * we switch to the final kernel address space
 */
fn try_early_boot_system<'h, 'l>(init: EarlyBootState<'h, 'l>) -> Result<PostEarlyBootState<'h>, PlatInterfaceType> {
    /* Initial the serial output of our platform first so that
     * we can get debugging output. */
    let mut plat = get_platform(&BootConfig);
    plat.init_serial();
    write!(plat, "R4: In early setup\n").unwrap();
    /* Initialize the panic function so we can see anything
     * really bad that happens */
    panic_set_plat(&mut plat);
    /* Now we can continue with the rest of init */
    if init.mbi_magic as u64 != multiboot::SIGNATURE_RAX {
        write!(plat,"Invalid multiboot signature!\nExpected {} got {} with pointer {:?}\n", multiboot::SIGNATURE_RAX, init.mbi_magic, init.mbi).unwrap();
        return Err(plat);
    }
    let mut mbi = MbiWrapper{mbi: None, callback: &|p, s| unsafe {
        Some(init.low_window.make_slice(p as usize, s))
        }};
    unsafe {
        /* Thanks to the stupidy in this function interface of requiring
         * an unsafe function we cannot pass a lambda expression. Since
         * a lambda cannot be made unsafe and we have no other way of
         * passing our state we just transmute the lambda. Unfortunately
         * this removes all type checking on our function :( */
        mbi.mbi = match multiboot::Multiboot::new(init.mbi as multiboot::PAddr, mbi.callback) {
            Some(mbi) => Some(mbi),
            None => {
                write!(plat,"Failed to create multiboot!\n").unwrap();
                return Err(plat)
                }
            };
        if let &Some(ref mbi) = &mbi.mbi {
            display_multiboot(&mut plat, &mbi);
        }
    }
    Ok(PostEarlyBootState{ plat: plat, phantom: PhantomData })
}

/* Represent the multiboot info pointer as a pointer to
 * a usize for the moment. This will allow us to get the
 * lifetimes correct, and we will fill in the correct
 * type later */
#[no_mangle]
pub extern fn boot_system(magic: usize, mbi: *const usize) {
    /* This *will* be our final kernel window, but it is not our window
     * yet. We create it here so that our temporary high kernel window,
     * which is a subset of the final kernel window, can be constructed
     * from it as having the same lifetime. This allows any references
     * created from the boot high kernel window being able to live on
     * into the final kernel window */
    let final_window = KernelWindow::default();
    /* this variable will hold our system state as returned by early boot */
    let mut boot;
    {
        /* Construct our system state for boot */
        let boot_high_window;
        unsafe {
            boot_high_window = final_window.subwindow(BootHighWindow::default());
        }
        /* whilst doing early boot we can also access things in low memory */
        let boot_low_window = BootLowWindow::default();
        let boot_state = EarlyBootState {
            high_window: &boot_high_window,
            low_window: &boot_low_window,
            mbi_magic: magic,
            mbi: mbi,
        };
        boot = match try_early_boot_system(boot_state) {
            Err(mut plat) => {
                    write!(plat, "Failed early init. hlt'ing\n").unwrap();
                    halt();
                },
            Ok(b) => b,
        };
        /* The 'plat' definition got moved into boot. Reset the panic location */
        panic_set_plat(&mut boot.plat);
    }
    unimplemented!()
}
<|endoftext|>


<commit_before>
use std::ascii::AsciiExt;
use std::iter::Peekable;

/**
 program ::= statement_list

 statement_list ::=
    statement
    | statement_list
    | .

 statement ::=
    directive
    | label
    | instruction
    | comment

 directive ::= "." <identifier> (<string_literal> | <numeric_literal>)

 label ::= <identifier> ":"
 */

use assembler::scanner::Token;

// MARK: - Instruction Formats

fn is_i0_instruction<'a>(instruction: &'a str) -> bool {
    match instruction.to_ascii_lowercase().as_str() {
        "nop" | "cls" | "ret" | "trap" | "trapret" => { true }
        _ => { false }
    }
}

fn is_iA_instruction<'a>(instruction: &'a str) -> bool {
    match instruction.to_ascii_lowercase().as_str() {
        "jp" | "call" => { true }
        _ => { false }
    }
}

// MARK: - Helper Macros

macro_rules! expect {
    ($scanner:expr, $expected:pat) => {{
        let token = $scanner.next().unwrap();
        match token {
            $expected => {}
            _ => {
                println!("Invalid token {:?}", token);
                return;
            }
        }
    }};
}

macro_rules! accept {
    ($scanner:expr, $expected:pat) => {{
        let mut accepted = false;
        if let Some(token) = $scanner.peek() {
            match token {
                $expected => { accepted = true; }
                _ => { }
            }
        }
        if accepted {
            $scanner.next();
        }
        accepted
    }}
}

// MARK: - State Handlers

fn syntax_error<'a, I>(scanner: &mut Peekable<I>) where I: Iterator<Item=Token<'a>> {
    /*
     An invalid token not matching a terminal or a non-terminal was reached.
     */
    println!("Unexpected {:?} found.", scanner.next().unwrap());
    println!("Terminating assembly.");
    scanner.last();
}

// MARK: - Helper Methods

fn accept_identifier<'a, I>(scanner: &mut Peekable<I>) -> Option<&'a str> where I: Iterator<Item=Token<'a>> {
    let mut value = None;
    if let Some(identifier_token) = scanner.peek() {
        match identifier_token {
            &Token::Identifier(string) => { value = Some(string); }
            _ => {}
        }
    }
    if let Some(_) = value {
        scanner.next();
    }
    value
}

fn accept_numeric_literal<'a, I>(scanner: &mut Peekable<I>) -> Option<usize> where I: Iterator<Item=Token<'a>> {
    let mut value = None;
    if let Some(numeric_literal_token) = scanner.peek() {
        match numeric_literal_token {
            &Token::NumericLiteral(numeric) => { value = Some(numeric); }
            _ => {}
        }
    }
    if let Some(_) = value {
        scanner.next();
    }
    value
}

fn accept_string_literal<'a, I>(scanner: &mut Peekable<I>) -> Option<&'a str> where I: Iterator<Item=Token<'a>> {
    let mut value = None;
    if let Some(string_literal_token) = scanner.peek() {
        match string_literal_token {
            &Token::StringLiteral(string) => { value = Some(string); }
            _ => {}
        }
    }
    if let Some(_) = value {
        scanner.next();
    }
    value
}

// MARK: - Rules

fn comment<'a, I>(scanner: &mut Peekable<I>) where I: Iterator<Item=Token<'a>> {
    expect!(scanner, Token::SingleLineComment(_));
}

fn label_or_instruction<'a, I>(scanner: &mut Peekable<I>) where I: Iterator<Item=Token<'a>> {
    let mut successful_evaluation = false;

    /*
     label ::= <identifier> ":"
     instruction ::=
        [i0] (nop/cls/ret/trap/trapret)
        [iA] (jp/call)
     */

    let identifier = accept_identifier(scanner).unwrap();

    // Defines a new label at the current evaluation point.
    if accept!(scanner, &Token::LabelMarker) {
        println!("LABEL({})", identifier);
        return;
    }

    // These instructions do not accept parameters.
    if is_i0_instruction(identifier) {
        println!("INSTRUCTION({})", identifier);
        return;
    }

    // These instructions accept an address parameter.
    if is_iA_instruction(identifier) {
        if let Some(address) = accept_numeric_literal(scanner) {
            println!("INSTRUCTION({} {})", identifier, address);
            return;
        }
    }

    // The subsequent tokens did not match the rule.
    if !successful_evaluation {
        syntax_error(scanner);
    }
}

fn directive<'a, I>(scanner: &mut Peekable<I>) where I: Iterator<Item=Token<'a>> {
    let mut successful_evaluation = false;

    /*
     directive ::= "." <identifier> (<string_literal> | <numeric_literal>)
     */
    expect!(scanner, Token::DirectiveMarker);

    // Extract the directive ID if possible.
    if let Some(identifier) = accept_identifier(scanner) {
        if let Some(numeric_literal) = accept_numeric_literal(scanner) {
            println!("Directive({}) Numeric({})", identifier, numeric_literal);
            successful_evaluation = true;
        }

        if let Some(string_literal) = accept_string_literal(scanner) {
            println!("Directive({}) String({})", identifier, string_literal);
            successful_evaluation = true;
        }
    }

    // The subsequent tokens did not match a directive declaration.
    if !successful_evaluation {
        syntax_error(scanner);
    }
}

fn statement<'a, I>(scanner: &mut Peekable<I>) where I: Iterator<Item=Token<'a>> {
    /*
     statement ::= comment | directive | label | instruction
     */
    let mut next_rule: fn(&mut Peekable<I>) -> () = syntax_error;

    // Continue parsing the input file until it yields no more tokens.
    if let Some(next_token) = scanner.peek() {
        next_rule = match next_token {
            &Token::SingleLineComment(_) => { comment }
            &Token::DirectiveMarker => { directive }
            &Token::Identifier(_) => { label_or_instruction }
            _ => { syntax_error }
        };
    }

    next_rule(scanner);
}

fn statement_list<'a, I>(scanner: &mut Peekable<I>) where I: Iterator<Item=Token<'a>> {
    /*
     statement_list ::= statement_list statement | statement | .
     */
    while let Some(_) = scanner.peek() {
        statement(scanner);
    }
}

pub fn parse<'a, I>(scanner: I) where I: Iterator<Item=Token<'a>> {
    /*
     program ::= statement_list
     */
    statement_list(&mut scanner.peekable());
}
<commit_msg>Next refactor attempt for the parser. Will try something yet simpler.<commit_after>
use std::ascii::AsciiExt;
use std::iter::Peekable;
use std::collections::BTreeMap;

/**
 program ::= statement_list

 statement_list ::=
    statement
    | statement_list
    | .

 statement ::=
    directive
    | label
    | instruction
    | comment

 directive ::= "." <identifier> (<string_literal> | <numeric_literal>)

 label ::= <identifier> ":"

 instruction ::= <identifier> instruction_args_for(instruction)
 */

use assembler::scanner::Token;

// MARK: - Helper Macros

macro_rules! peek {
    ($scanner:expr,$p:pat) => {{
        if let Some(token) = $scanner.peek() {
            match *token {
                $p => { true  }
                 _ => { false }
            }
        } else {
            false
        }
    }}
}

macro_rules! accept {
    ($scanner:expr,$p:pat) => {{
        if peek!($scanner, $p) {
            (true, $scanner.next())
        } else {
            (false, None)
        }
    }}
}

// MARK: - Type Definitions

type ParseResult = Result<(), String>;

// MARK: - Parser Object

struct Parser<'a,I> where I: Iterator<Item=Token<'a>> {
    /// Peekable iterator over input token stream.
    scanner: Peekable<I>,
    /// Stack of value-type tokens (Identifier, StringLiteral, NumericLiteral).
    value_stack: Vec<Token<'a>>,
    /// A map of labels and their corresponding addresses.
    label_map: BTreeMap<&'a str, usize>,
    /// Current address.
    current_address: usize
}

impl<'a,I> Parser<'a,I> where I: Iterator<Item=Token<'a>> {

    fn new(scanner: I) -> Parser<'a, I> {
        Parser {
            scanner: scanner.peekable(),
            value_stack: Vec::new(),
            label_map: BTreeMap::new(),
            current_address: 0
        }
    }

    /// MARK: - Expecting values.

    fn accept_identifier(&mut self) -> Option<&'a str> {
        if let (true, Some(Token::Identifier(string))) = accept!(self.scanner, Token::Identifier(_)) {
            Some(string)
        } else {
            None
        }
    }

    fn accept_string(&mut self) -> Option<&'a str> {
        if let (true, Some(Token::StringLiteral(string))) = accept!(self.scanner, Token::StringLiteral(_)) {
            Some(string)
        } else {
            None
        }
    }

    fn accept_numeric(&mut self) -> Option<usize> {
        if let (true, Some(Token::NumericLiteral(number))) = accept!(self.scanner, Token::NumericLiteral(_)) {
            Some(number)
        } else {
            None
        }
    }

    /// MARK: - Non-terminal Symbols.

    pub fn parse(&mut self) -> ParseResult {
        /*
         statement_list ::= statement | statement_list | .
         */
        while let Some(_) = self.scanner.peek() {
            try!(self.parse_statement());
        }
        Ok(())
    }

    fn parse_statement(&mut self) -> ParseResult {
        /*
         statement ::= comment | directive | label | instruction
         */

        // Consume the single-line comment token as it appears.
        if let (true, _) = accept!(self.scanner, Token::SingleLineComment(_)) {
            return Ok(());
        }

        // A directive begins with a directive marker token.
        if peek!(self.scanner, Token::DirectiveMarker) {
            return self.parse_directive();
        }

        if let Some(identifier) = self.accept_identifier() {
            /*
                   label ::= <identifier> ":"
             instruction ::= <identifier> instruction_args_for(instruction)
             */

            // Both 'instruction' and 'label' begin with identifiers, and label is proceeded by a LabelIdentifier.
            if let (true, _) = accept!(self.scanner, Token::LabelMarker) {
                return self.interpret_label(identifier);
            }

            // This must, therefore, be an instruction.
            return self.parse_instruction_args_with_identifier(identifier);
        }

        Err(format!("Unable to parse statement"))
    }

    fn parse_directive(&mut self) -> ParseResult {
        /*
         directive ::= <identifier> (<string_literal> | <numeric_literal>)
         */

        // Expect the presence of  directive marker.
        if let (false, None) = accept!(self.scanner, Token::DirectiveMarker) {
            return Err(format!("Unexpected token {:?}. Expecting directive marker.", self.scanner.peek()));
        }

        // Expect the presence of an identifier.
        let directive = if let Some(identifier) = self.accept_identifier() {
            identifier
        } else {
            return Err(format!("Expected identifier after directive marker."));
        };

        // Expect either a numeric or a string literal, and interpret accordingly.
        if let Some(string) = self.accept_string() {
            self.interpret_directive_s(directive, string)
        } else if let Some(numeric) = self.accept_numeric() {
            self.interpret_directive_n(directive, numeric)
        } else {
            Err(format!("Expected literal (string or numeric) for directive .{}", directive))
        }
    }

    fn parse_instruction_args_with_identifier(&mut self, instruction: &'a str) -> ParseResult {
        /*
         instruction ::= <identifier> instruction_args_for(instruction)
         */
        Ok(())
    }

    /// MARK: - Interpreters.

    fn interpret_directive_s(&mut self, name: &'a str, string_arg: &'a str) -> ParseResult {
        println!("Directive<Type=String>('{}', '{}')", name, string_arg);

        // Emit a string literal.
        if name.eq_ignore_ascii_case("db") {
            return Ok(())
        }

        Err(format!("Unknown directive {} [Type=String] ('{}')", name, string_arg))
    }

    fn interpret_directive_n(&mut self, name: &'a str, numeric_arg: usize) -> ParseResult {
        println!("Directive<Type=Numeric>('{}', ${:X})", name, numeric_arg);

        // Set the current output address for the assembly.
        if name.eq_ignore_ascii_case("org") {
            self.current_address = numeric_arg;
            return Ok(())
        }

        // Emit a single byte numeric literal.
        if name.eq_ignore_ascii_case("db") {
            if (numeric_arg & 0xFF) != 0 {
                return Err(format!("Cannot emit byte with numeric value > 0xFF (was ${:X})", numeric_arg));
            } else {
                return Ok(());
            }
        }

        Err(format!("Unknown directive {} [Type=Numeric] (${:X})", name, numeric_arg))
    }

    fn interpret_label(&mut self, name: &'a str) -> ParseResult {
        // An attempt was made to re-define the label.
        if let Some(&existing_address) = self.label_map.get(name) {
            return Err(format!("Attempted re-definition of label '{}' (${:X}) to ${:X}", name, existing_address, self.current_address))
        }

        // Store the current address in the label map.
        println!("DefineLabel('{}') = ${:X}", name, self.current_address);
        self.label_map.insert(name, self.current_address);
        Ok(())
    }

}

// MARK: - Parse Function

pub fn parse<'a, I>(scanner: I) where I: Iterator<Item=Token<'a>> {
    let mut parser = Parser::new(scanner);
    println!("{:?}", parser.parse());
}
<|endoftext|>