<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::ffi::OsString;
use std::fs;
use std::io::{ErrorKind, Read};
use std::os::unix::net::UnixListener;
use std::path::{Path, PathBuf};
use std::process::{Child, Command};
use std::rc::Rc;
use std::time::Duration;

use anyhow::{bail, Context, Result};
use log;
use nix::sys::signal::{self, Signal};
use nix::unistd::Pid;

use crate::io::emu::{EmuError, EmuState, EmuValue, Emulator};
use crate::transport::ti50emulator::Inner;
use crate::transport::ti50emulator::Ti50Emulator;

const TIMEOUT: Duration = Duration::from_millis(1000);
const MAX_RETRY: usize = 5;
const PATTERN: &[u8; 5] = b"READY";

pub struct EmulatorProcess {
    /// Current working directory for Emulator sub-process.
    runtime_directory: PathBuf,
    /// Directory with contain TockOS Applications and Kernel.
    executable_directory: PathBuf,
    /// Default name of TockOS kernel file.
    executable: String,
    /// Map of currently used argument by kernel.
    current_args: HashMap<String, EmuValue>,
    /// Current state of Emulator.
    state: EmuState,
    /// Handle to Emulator sub-proccess.
    proc: Option<Child>,
}

impl EmulatorProcess {
    /// Create new instance of [`EmulatorProcess`] based on provided parameters.
    pub fn init(
        instance_directory: &Path,
        executable_directory: &Path,
        executable: &str,
    ) -> Result<Self> {
        let runtime_directory = instance_directory.join("runtime");
        fs::create_dir(&runtime_directory).context("Failed to create runtime directory")?;
        Ok(Self {
            executable_directory: executable_directory.to_owned(),
            executable: executable.to_owned(),
            runtime_directory: runtime_directory.clone(),
            current_args: HashMap::from([(
                String::from("exec"),
                EmuValue::String(String::from(executable)),
            )]),
            state: EmuState::Off,
            proc: None,
        })
    }

    /// Updates `state` based on sub-process exit status and current value of `state`.
    fn update_status(&mut self) -> Result<()> {
        if let Some(proc) = &mut self.proc {
            match proc.try_wait() {
                Ok(Some(status)) => {
                    if status.success() {
                        log::info!("Ti50Emulator exit with status {}", status);
                        self.state = EmuState::Off;
                    } else {
                        if self.state != EmuState::Error {
                            log::info!("Ti50Emulator sub-process exit with error: {}", status);
                            self.state = EmuState::Error;
                        }
                    }
                    self.proc = None;
                }
                Ok(None) => {
                    self.state = EmuState::On;
                }
                Err(err) => {
                    bail!(EmuError::RuntimeError(format!(
                        "Can't aquire status from sub-process pid:{} error:{}",
                        proc.id(),
                        err
                    )));
                }
            }
        } else {
            if self.state == EmuState::On {
                self.state = EmuState::Error;
                bail!(EmuError::RuntimeError(
                    "Non sub-process found but state indicate that Emulator is ON".to_string()
                ));
            }
        }
        Ok(())
    }

    /// Run Emulator executable as sub-process and wait until Emulator is ready to work.
    fn spawn_process(&mut self) -> Result<()> {
        let socket_path = self.runtime_directory.join("control_soc");
        let control_socket = UnixListener::bind(&socket_path)?;
        control_socket
            .set_nonblocking(true)
            .context("Set non-blocking to socket fail")?;

        let mut args_list = Vec::new();

        args_list.push(OsString::from("--path"));
        args_list.push(self.runtime_directory.clone().into_os_string());

        args_list.push(OsString::from("--control_socket"));
        args_list.push(socket_path.into_os_string());

        match self.current_args.get("apps") {
            Some(EmuValue::StringList(apps)) => {
                args_list.push(OsString::from("--apps"));
                args_list.extend(
                    apps.iter()
                        .map(|a| self.executable_directory.join(a).into()),
                );
            }
            None => {
                bail!(EmuError::StartFailureCause(
                    "Ti50 sub-process missing application list".to_string()
                ))
            }
            _ => {
                bail!(EmuError::StartFailureCause(
                    "Ti50 sub-process expect apps to be list of string".to_string()
                ));
            }
        }

        let exec = match self.current_args.get("exec") {
            Some(EmuValue::String(exec_name)) => self.executable_directory.join(exec_name),
            None => {
                bail!(EmuError::StartFailureCause(
                    "Ti50 sub-process invalid executable".to_string()
                ))
            }
            _ => {
                bail!(EmuError::StartFailureCause(
                    "Ti50 sub-process except exec name to be string".to_string()
                ))
            }
        };

        log::info!("Spawning Ti50Emulator sub-process");
        log::info!("Command: {} {:?}", exec.display(), args_list);
        let handle = Command::new(&exec)
            .args(args_list)
            .spawn()
            .context("Could not spawn sub-process")?;
        self.proc = Some(handle);
        let mut buffer = [0u8, 8];
        let mut retry = 0;
        while retry < MAX_RETRY {
            match control_socket.accept() {
                Ok((mut socket, _address)) => {
                    let len = socket
                        .read(&mut buffer)
                        .context("Control socket read error")?;
                    if len >= PATTERN.len() && PATTERN[..] == buffer[0..PATTERN.len()] {
                        log::info!("Ti50Emulator ready");
                        return Ok(());
                    }
                }
                Err(err) if err.kind() == ErrorKind::WouldBlock => {
                    log::debug!("Wait for sub-process...");
                    std::thread::sleep(TIMEOUT);
                }
                Err(err) => {
                    self.state = EmuState::Error;
                    bail!(EmuError::StartFailureCause(format!(
                        "Can't connect to other end of sub-process control socket error:{}",
                        err
                    )));
                }
            }
            retry += 1;
        }
        Err(EmuError::StartFailureCause(format!(
            "Ti50 sub-process spawn failure to many tries MAX_RETRY: {}",
            MAX_RETRY
        ))
        .into())
    }

    /// The function tries to safely terminate the Emulator sub-process.
    /// If the sub-process does not finish its execution after time
    /// described in `TIMEOUT` * `MAX_RETRY`, use SIGKILL to force sub-process termination.
    /// If all method fail, it returns an EmuError.
    fn stop_process(&mut self) -> Result<()> {
        if let Some(handle) = &self.proc {
            let pid = handle.id() as i32;
            signal::kill(Pid::from_raw(pid), Signal::SIGTERM)
                .context("Stop sub-process using SIGTERM")?;
            for _retry in 0..MAX_RETRY {
                std::thread::sleep(TIMEOUT);
                match signal::kill(Pid::from_raw(pid), None) {
                    Ok(()) => {}
                    Err(nix::Error::Sys(nix::errno::Errno::ESRCH)) => {
                        self.state = EmuState::Off;
                        self.proc = None;
                        return Ok(());
                    }
                    Err(e) => {
                        self.state = EmuState::Error;
                        bail!(EmuError::StopFailureCause(format!(
                            "Unexpected error querying process presence: {}",
                            e
                        )));
                    }
                }
            }
            signal::kill(Pid::from_raw(pid), Signal::SIGKILL)
                .context("Stop sub-process using SIGKILL")?;
            std::thread::sleep(TIMEOUT);
            match signal::kill(Pid::from_raw(pid), None) {
                Err(nix::Error::Sys(nix::errno::Errno::ESRCH)) => {
                    self.proc = None;
                    self.state = EmuState::Off;
                    return Ok(());
                }
                _ => {
                    self.proc = None;
                    self.state = EmuState::Error;
                    bail!(EmuError::StopFailureCause(format!(
                        "Unable to stop process pid:{}",
                        pid
                    )));
                }
            }
        }
        Ok(())
    }

    /// Method reset all internal states of Emulator to its default values.
    fn reset_state(&mut self) -> Result<()> {
        fs::remove_dir_all(&self.runtime_directory)?;
        fs::create_dir(&self.runtime_directory)?;
        self.current_args.clear();
        self.current_args.insert(
            String::from("exec"),
            EmuValue::String(self.executable.clone()),
        );
        Ok(())
    }

    /// Update content of resource with data from `source`, overwrite file if it already exist.
    fn update_resource(&self, key: &str, source: &Path) -> Result<()> {
        let name = source.file_name().ok_or(EmuError::InvalidArgumentValue(
            String::from(key),
            source.display().to_string(),
        ))?;
        let destination = self.runtime_directory.join(name);
        log::debug!(
            "Update resource:{:?} with data from path: {:?}",
            key,
            source,
        );
        fs::copy(&source, &destination).with_context(|| {
            format!(
                "Failed to copy resource file: {} to runtime directory: {}",
                &source.display(),
                &destination.display()
            )
        })?;
        Ok(())
    }

    /// Method update state files and parameters passed to Emulator sub-process.
    /// If `factory_reset` is set to true old resource files stored in runtime_directory will be removed and
    /// current_args will be set to its default value.
    /// Values from parameter `args` is used to update value of current argument set passed to
    /// sub-process. If `args` contains paths to files they will be copied to the runtime directory.
    fn update_args(&mut self, factory_reset: bool, args: &HashMap<String, EmuValue>) -> Result<()> {
        let allowed = HashSet::from(["exec", "flash", "apps", "version_state", "pmu_state"]);
        let mandatory = ["exec", "apps"];
        for &name in mandatory.iter() {
            if !self.current_args.contains_key(name) && !args.contains_key(name) {
                bail!(EmuError::StartFailureCause(format!(
                    "Missing argument {}",
                    name
                )))
            }
        }
        if factory_reset {
            self.reset_state()?;
        }
        for (key, item) in args.iter() {
            if allowed.contains(key.as_str()) {
                match item {
                    EmuValue::FilePath(path) => {
                        self.update_resource(&key, path)?;
                    }
                    EmuValue::FilePathList(path_list) => {
                        for path in path_list.iter() {
                            self.update_resource(&key, path)?;
                        }
                    }
                    _ => {}
                }
                self.current_args.insert(key.clone(), item.clone());
                continue;
            }
            bail!(EmuError::InvalidArgumetName(key.clone()));
        }
        Ok(())
    }
}

/// Structure representing `Emulator` sub-process based on TockOS host-emulation architecture.
pub struct Ti50SubProcess {
    inner: Rc<RefCell<Inner>>,
}

impl Ti50SubProcess {
    /// Create a new `Ti50SubProcess` instance.
    pub fn open(ti50: &Ti50Emulator) -> Result<Self> {
        Ok(Self {
            inner: ti50.inner.clone(),
        })
    }
}

impl Emulator for Ti50SubProcess {
    /// Simple function with return `EmuState` representing current state of Emulator instance.
    fn get_state(&self) -> Result<EmuState> {
        let process = &mut self.inner.borrow_mut().process;
        process.update_status()?;
        Ok(process.state)
    }

    /// Start emulator sub-process with provided arguments.
    fn start(&self, factory_reset: bool, args: &HashMap<String, EmuValue>) -> Result<()> {
        let process = &mut self.inner.borrow_mut().process;
        process.update_status()?;
        match process.state {
            EmuState::On => {
                bail!(EmuError::StartFailureCause(String::from(
                    "DUT is already running",
                )));
            }
            EmuState::Busy => {
                bail!(EmuError::StartFailureCause(String::from(
                    "DUT is in transient state BUSY",
                )));
            }
            EmuState::Error => {
                log::debug!("DUT trying to recover after error");
            }
            _ => {}
        };
        process.state = EmuState::Busy;
        process.update_args(factory_reset, args)?;
        process.spawn_process()?;
        process.state = EmuState::On;
        Ok(())
    }

    /// Stop emulator sub-process.
    fn stop(&self) -> Result<()> {
        let process = &mut self.inner.borrow_mut().process;
        process.update_status()?;
        match process.state {
            EmuState::Off => {
                bail!(EmuError::StopFailureCause(String::from(
                    "DUT is alredy Off"
                ),));
            }
            EmuState::Busy => {
                bail!(EmuError::StopFailureCause(String::from(
                    "DUT is in transient state BUSY"
                ),));
            }
            EmuState::Error => {
                log::info!("DUT stop after error");
            }
            _ => {}
        }
        process.stop_process()?;
        Ok(())
    }
}
<commit_msg>[opentitanlib] Add ID to Ti50Emulator SubProcess<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::ffi::OsString;
use std::fs;
use std::io::{ErrorKind, Read};
use std::os::unix::net::UnixListener;
use std::path::{Path, PathBuf};
use std::process::{Child, Command};
use std::rc::Rc;
use std::time::Duration;

use anyhow::{bail, Context, Result};
use log;
use nix::sys::signal::{self, Signal};
use nix::unistd::Pid;

use crate::io::emu::{EmuError, EmuState, EmuValue, Emulator};
use crate::transport::ti50emulator::Inner;
use crate::transport::ti50emulator::Ti50Emulator;

const TIMEOUT: Duration = Duration::from_millis(1000);
const MAX_RETRY: usize = 5;
const PATTERN: &[u8; 5] = b"READY";
pub const EMULATOR_INVALID_ID: u64 = 0;

pub struct EmulatorProcess {
    /// Current working directory for Emulator sub-process.
    runtime_directory: PathBuf,
    /// Directory with contain TockOS Applications and Kernel.
    executable_directory: PathBuf,
    /// Default name of TockOS kernel file.
    executable: String,
    /// Map of currently used argument by kernel.
    current_args: HashMap<String, EmuValue>,
    /// Current state of Emulator.
    state: EmuState,
    /// Handle to Emulator sub-proccess.
    proc: Option<Child>,
    /// Counter of 'power' cycle
    power_cycle_count: u32,
}

impl EmulatorProcess {
    /// Create new instance of [`EmulatorProcess`] based on provided parameters.
    pub fn init(
        instance_directory: &Path,
        executable_directory: &Path,
        executable: &str,
    ) -> Result<Self> {
        let runtime_directory = instance_directory.join("runtime");
        fs::create_dir(&runtime_directory).context("Failed to create runtime directory")?;
        Ok(Self {
            executable_directory: executable_directory.to_owned(),
            executable: executable.to_owned(),
            runtime_directory: runtime_directory.clone(),
            current_args: HashMap::from([(
                String::from("exec"),
                EmuValue::String(String::from(executable)),
            )]),
            state: EmuState::Off,
            proc: None,
            power_cycle_count: 1,
        })
    }

    pub fn get_state(&self) -> EmuState {
        self.state
    }

    pub fn get_runtime_dir(&self) -> &Path {
        &self.runtime_directory
    }

    pub fn get_id(&self) -> u64 {
        if let Some(proc) = &self.proc {
            return ((self.power_cycle_count as u64) << 32) + (proc.id() as u64);
        }
        return EMULATOR_INVALID_ID;
    }

    /// Updates `state` based on sub-process exit status and current value of `state`.
    pub fn update_status(&mut self) -> Result<()> {
        if let Some(proc) = &mut self.proc {
            match proc.try_wait() {
                Ok(Some(status)) => {
                    if status.success() {
                        log::info!("Ti50Emulator exit with status {}", status);
                        self.state = EmuState::Off;
                    } else {
                        if self.state != EmuState::Error {
                            log::info!("Ti50Emulator sub-process exit with error: {}", status);
                            self.state = EmuState::Error;
                        }
                    }
                    self.power_cycle_count += 1;
                    self.proc = None;
                }
                Ok(None) => {
                    self.state = EmuState::On;
                }
                Err(err) => {
                    bail!(EmuError::RuntimeError(format!(
                        "Can't aquire status from sub-process pid:{} error:{}",
                        proc.id(),
                        err
                    )));
                }
            }
        } else {
            if self.state == EmuState::On {
                self.state = EmuState::Error;
                bail!(EmuError::RuntimeError(
                    "Non sub-process found but state indicate that Emulator is ON".to_string()
                ));
            }
        }
        Ok(())
    }

    /// Run Emulator executable as sub-process and wait until Emulator is ready to work.
    fn spawn_process(&mut self) -> Result<()> {
        let socket_path = self.runtime_directory.join("control_soc");
        let control_socket = UnixListener::bind(&socket_path)?;
        control_socket
            .set_nonblocking(true)
            .context("Set non-blocking to socket fail")?;

        let mut args_list = Vec::new();

        args_list.push(OsString::from("--path"));
        args_list.push(self.runtime_directory.clone().into_os_string());

        args_list.push(OsString::from("--control_socket"));
        args_list.push(socket_path.into_os_string());

        match self.current_args.get("apps") {
            Some(EmuValue::StringList(apps)) => {
                args_list.push(OsString::from("--apps"));
                args_list.extend(
                    apps.iter()
                        .map(|a| self.executable_directory.join(a).into()),
                );
            }
            None => {
                bail!(EmuError::StartFailureCause(
                    "Ti50 sub-process missing application list".to_string()
                ))
            }
            _ => {
                bail!(EmuError::StartFailureCause(
                    "Ti50 sub-process expect apps to be list of string".to_string()
                ));
            }
        }

        let exec = match self.current_args.get("exec") {
            Some(EmuValue::String(exec_name)) => self.executable_directory.join(exec_name),
            None => {
                bail!(EmuError::StartFailureCause(
                    "Ti50 sub-process invalid executable".to_string()
                ))
            }
            _ => {
                bail!(EmuError::StartFailureCause(
                    "Ti50 sub-process except exec name to be string".to_string()
                ))
            }
        };

        log::info!("Spawning Ti50Emulator sub-process");
        log::info!("Command: {} {:?}", exec.display(), args_list);
        let handle = Command::new(&exec)
            .args(args_list)
            .spawn()
            .context("Could not spawn sub-process")?;
        self.proc = Some(handle);
        let mut buffer = [0u8, 8];
        let mut retry = 0;
        while retry < MAX_RETRY {
            match control_socket.accept() {
                Ok((mut socket, _address)) => {
                    let len = socket
                        .read(&mut buffer)
                        .context("Control socket read error")?;
                    if len >= PATTERN.len() && PATTERN[..] == buffer[0..PATTERN.len()] {
                        log::info!("Ti50Emulator ready");
                        return Ok(());
                    }
                }
                Err(err) if err.kind() == ErrorKind::WouldBlock => {
                    log::debug!("Wait for sub-process...");
                    std::thread::sleep(TIMEOUT);
                }
                Err(err) => {
                    self.state = EmuState::Error;
                    bail!(EmuError::StartFailureCause(format!(
                        "Can't connect to other end of sub-process control socket error:{}",
                        err
                    )));
                }
            }
            retry += 1;
        }
        Err(EmuError::StartFailureCause(format!(
            "Ti50 sub-process spawn failure to many tries MAX_RETRY: {}",
            MAX_RETRY
        ))
        .into())
    }

    /// The function tries to safely terminate the Emulator sub-process.
    /// If the sub-process does not finish its execution after time
    /// described in `TIMEOUT` * `MAX_RETRY`, use SIGKILL to force sub-process termination.
    /// If all method fail, it returns an EmuError.
    fn stop_process(&mut self) -> Result<()> {
        self.power_cycle_count += 1;
        if let Some(handle) = &self.proc {
            let pid = handle.id() as i32;
            signal::kill(Pid::from_raw(pid), Signal::SIGTERM)
                .context("Stop sub-process using SIGTERM")?;
            for _retry in 0..MAX_RETRY {
                std::thread::sleep(TIMEOUT);
                match signal::kill(Pid::from_raw(pid), None) {
                    Ok(()) => {}
                    Err(nix::Error::Sys(nix::errno::Errno::ESRCH)) => {
                        self.state = EmuState::Off;
                        self.proc = None;
                        return Ok(());
                    }
                    Err(e) => {
                        self.state = EmuState::Error;
                        bail!(EmuError::StopFailureCause(format!(
                            "Unexpected error querying process presence: {}",
                            e
                        )));
                    }
                }
            }
            signal::kill(Pid::from_raw(pid), Signal::SIGKILL)
                .context("Stop sub-process using SIGKILL")?;
            std::thread::sleep(TIMEOUT);
            match signal::kill(Pid::from_raw(pid), None) {
                Err(nix::Error::Sys(nix::errno::Errno::ESRCH)) => {
                    self.proc = None;
                    self.state = EmuState::Off;
                    return Ok(());
                }
                _ => {
                    self.proc = None;
                    self.state = EmuState::Error;
                    bail!(EmuError::StopFailureCause(format!(
                        "Unable to stop process pid:{}",
                        pid
                    )));
                }
            }
        }
        Ok(())
    }

    /// Method reset all internal states of Emulator to its default values.
    fn reset_state(&mut self) -> Result<()> {
        fs::remove_dir_all(&self.runtime_directory)?;
        fs::create_dir(&self.runtime_directory)?;
        self.current_args.clear();
        self.current_args.insert(
            String::from("exec"),
            EmuValue::String(self.executable.clone()),
        );
        Ok(())
    }

    /// Update content of resource with data from `source`, overwrite file if it already exist.
    fn update_resource(&self, key: &str, source: &Path) -> Result<()> {
        let name = source.file_name().ok_or(EmuError::InvalidArgumentValue(
            String::from(key),
            source.display().to_string(),
        ))?;
        let destination = self.runtime_directory.join(name);
        log::debug!(
            "Update resource:{:?} with data from path: {:?}",
            key,
            source,
        );
        fs::copy(&source, &destination).with_context(|| {
            format!(
                "Failed to copy resource file: {} to runtime directory: {}",
                &source.display(),
                &destination.display()
            )
        })?;
        Ok(())
    }

    /// Method update state files and parameters passed to Emulator sub-process.
    /// If `factory_reset` is set to true old resource files stored in runtime_directory will be removed and
    /// current_args will be set to its default value.
    /// Values from parameter `args` is used to update value of current argument set passed to
    /// sub-process. If `args` contains paths to files they will be copied to the runtime directory.
    fn update_args(&mut self, factory_reset: bool, args: &HashMap<String, EmuValue>) -> Result<()> {
        let allowed = HashSet::from(["exec", "flash", "apps", "version_state", "pmu_state"]);
        let mandatory = ["exec", "apps"];
        for &name in mandatory.iter() {
            if !self.current_args.contains_key(name) && !args.contains_key(name) {
                bail!(EmuError::StartFailureCause(format!(
                    "Missing argument {}",
                    name
                )))
            }
        }
        if factory_reset {
            self.reset_state()?;
        }
        for (key, item) in args.iter() {
            if allowed.contains(key.as_str()) {
                match item {
                    EmuValue::FilePath(path) => {
                        self.update_resource(&key, path)?;
                    }
                    EmuValue::FilePathList(path_list) => {
                        for path in path_list.iter() {
                            self.update_resource(&key, path)?;
                        }
                    }
                    _ => {}
                }
                self.current_args.insert(key.clone(), item.clone());
                continue;
            }
            bail!(EmuError::InvalidArgumetName(key.clone()));
        }
        Ok(())
    }
}

/// Structure representing `Emulator` sub-process based on TockOS host-emulation architecture.
pub struct Ti50SubProcess {
    inner: Rc<RefCell<Inner>>,
}

impl Ti50SubProcess {
    /// Create a new `Ti50SubProcess` instance.
    pub fn open(ti50: &Ti50Emulator) -> Result<Self> {
        Ok(Self {
            inner: ti50.inner.clone(),
        })
    }
}

impl Emulator for Ti50SubProcess {
    /// Simple function with return `EmuState` representing current state of Emulator instance.
    fn get_state(&self) -> Result<EmuState> {
        let process = &mut self.inner.borrow_mut().process;
        process.update_status()?;
        Ok(process.state)
    }

    /// Start emulator sub-process with provided arguments.
    fn start(&self, factory_reset: bool, args: &HashMap<String, EmuValue>) -> Result<()> {
        let process = &mut self.inner.borrow_mut().process;
        process.update_status()?;
        match process.state {
            EmuState::On => {
                bail!(EmuError::StartFailureCause(String::from(
                    "DUT is already running",
                )));
            }
            EmuState::Busy => {
                bail!(EmuError::StartFailureCause(String::from(
                    "DUT is in transient state BUSY",
                )));
            }
            EmuState::Error => {
                log::debug!("DUT trying to recover after error");
            }
            _ => {}
        };
        process.state = EmuState::Busy;
        process.update_args(factory_reset, args)?;
        process.spawn_process()?;
        process.state = EmuState::On;
        Ok(())
    }

    /// Stop emulator sub-process.
    fn stop(&self) -> Result<()> {
        let process = &mut self.inner.borrow_mut().process;
        process.update_status()?;
        match process.state {
            EmuState::Off => {
                bail!(EmuError::StopFailureCause(String::from(
                    "DUT is alredy Off"
                ),));
            }
            EmuState::Busy => {
                bail!(EmuError::StopFailureCause(String::from(
                    "DUT is in transient state BUSY"
                ),));
            }
            EmuState::Error => {
                log::info!("DUT stop after error");
            }
            _ => {}
        }
        process.stop_process()?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>use proc_macro2::{Ident, Span, TokenStream};
use quote::ToTokens;
use syn::LitStr;

use std::ops::{Deref, DerefMut};

/// An entity with a span attached.
#[derive(Debug, Clone)]
pub struct Sp<T> {
    span: Span,
    val: T,
}

impl<T> Sp<T> {
    pub fn new(val: T, span: Span) -> Self {
        Sp { val, span }
    }

    pub fn call_site(val: T) -> Self {
        Sp {
            val,
            span: Span::call_site(),
        }
    }

    pub fn span(&self) -> Span {
        self.span
    }
}

impl<T> Deref for Sp<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.val
    }
}

impl<T> DerefMut for Sp<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.val
    }
}

impl From<Ident> for Sp<String> {
    fn from(ident: Ident) -> Self {
        Sp {
            val: ident.to_string(),
            span: ident.span(),
        }
    }
}

impl From<LitStr> for Sp<String> {
    fn from(lit: LitStr) -> Self {
        Sp {
            val: lit.value(),
            span: lit.span(),
        }
    }
}

impl<'a> From<Sp<&'a str>> for Sp<String> {
    fn from(sp: Sp<&'a str>) -> Self {
        Sp::new(sp.val.into(), sp.span)
    }
}

impl<U, T: PartialEq<U>> PartialEq<U> for Sp<T> {
    fn eq(&self, other: &U) -> bool {
        self.val == *other
    }
}

impl<T: AsRef<str>> AsRef<str> for Sp<T> {
    fn as_ref(&self) -> &str {
        self.val.as_ref()
    }
}

impl<T: ToTokens> ToTokens for Sp<T> {
    fn to_tokens(&self, stream: &mut TokenStream) {
        // this is the simplest way out of correct ones to change span on
        // arbitrary token tree I could come up with
        let tt = self.val.to_token_stream().into_iter().map(|mut tt| {
            tt.set_span(self.span.clone());
            tt
        });

        stream.extend(tt);
    }
}
<commit_msg>fix: cargo fmt + clippy<commit_after>use proc_macro2::{Ident, Span, TokenStream};
use quote::ToTokens;
use syn::LitStr;

use std::ops::{Deref, DerefMut};

/// An entity with a span attached.
#[derive(Debug, Clone)]
pub struct Sp<T> {
    span: Span,
    val: T,
}

impl<T> Sp<T> {
    pub fn new(val: T, span: Span) -> Self {
        Sp { val, span }
    }

    pub fn call_site(val: T) -> Self {
        Sp {
            val,
            span: Span::call_site(),
        }
    }

    pub fn span(&self) -> Span {
        self.span
    }
}

impl<T> Deref for Sp<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.val
    }
}

impl<T> DerefMut for Sp<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.val
    }
}

impl From<Ident> for Sp<String> {
    fn from(ident: Ident) -> Self {
        Sp {
            val: ident.to_string(),
            span: ident.span(),
        }
    }
}

impl From<LitStr> for Sp<String> {
    fn from(lit: LitStr) -> Self {
        Sp {
            val: lit.value(),
            span: lit.span(),
        }
    }
}

impl<'a> From<Sp<&'a str>> for Sp<String> {
    fn from(sp: Sp<&'a str>) -> Self {
        Sp::new(sp.val.into(), sp.span)
    }
}

impl<U, T: PartialEq<U>> PartialEq<U> for Sp<T> {
    fn eq(&self, other: &U) -> bool {
        self.val == *other
    }
}

impl<T: AsRef<str>> AsRef<str> for Sp<T> {
    fn as_ref(&self) -> &str {
        self.val.as_ref()
    }
}

impl<T: ToTokens> ToTokens for Sp<T> {
    fn to_tokens(&self, stream: &mut TokenStream) {
        // this is the simplest way out of correct ones to change span on
        // arbitrary token tree I could come up with
        let tt = self.val.to_token_stream().into_iter().map(|mut tt| {
            tt.set_span(self.span);
            tt
        });

        stream.extend(tt);
    }
}
<|endoftext|>


<commit_before>use std::ops::{AddAssign, Range};
use std::iter;
use std::collections::HashMap;

use alga::linear::FiniteDimInnerSpace;
use na::{self, Real, DMatrix, DVector, DVectorSlice, DVectorSliceMut, VectorSliceMutN, LU, Dynamic, Vector2, Point3};
use ncollide::utils;
use ncollide::procedural::{self, IndexBuffer};
use ncollide::shape::{TriMesh, DeformationsType, TetrahedronPointLocation, Triangle};
use ncollide::query::PointQueryWithLocation;

use object::{Body, BodyPart, BodyHandle, BodyPartHandle, BodyStatus, ActivationStatus};
use solver::{IntegrationParameters, ForceDirection};
use math::{Force, Inertia, Velocity, Vector, Point, Isometry, DIM, Dim};

/// A triangular element of the mass-spring surface.
#[derive(Clone)]
pub struct MassSpringElement<N: Real> {
    handle: Option<BodyPartHandle>,
    indices: Point3<usize>,
    surface: N,
}

#[derive(Clone)]
struct Spring<N: Real> {
    elements: (usize, usize),
    rest_length: N,
}

impl<N: Real> Spring<N> {
    fn new(elements: (usize, usize), rest_length: N) -> Self {
        Spring {
            elements,
            rest_length,
        }
    }

    fn from_positions(elements: (usize, usize), positions: &[N]) -> Self {
        let p0 = Point::from_slice(&positions[elements.0..elements.0 + DIM]);
        let p1 = Point::from_slice(&positions[elements.1..elements.1 + DIM]);
        let rest_length = na::distance(&p0, &p1);

        Spring {
            elements,
            rest_length,
        }
    }
}

/// A deformable surface using a mass-spring model with triangular elements.
#[derive(Clone)]
pub struct MassSpringSurface<N: Real> {
    handle: Option<BodyHandle>,
    springs: Vec<Spring<N>>,
    elements: Vec<MassSpringElement<N>>,
    positions: DVector<N>,
    velocities: DVector<N>,
    accelerations: DVector<N>,
    augmented_mass: DMatrix<N>,
    inv_augmented_mass: LU<N, Dynamic, Dynamic>,

    companion_id: usize,
    activation: ActivationStatus<N>,
    status: BodyStatus,
    stiffness: N,
    mass: N,
}

impl<N: Real> MassSpringSurface<N> {
    /// Creates a new deformable surface following the mass-spring model.
    ///
    /// The surface is initialized with a set of links corresponding to each trimesh edges.
    pub fn new(mesh: &TriMesh<N>, mass: N, stiffness: N) -> Self {
        let ndofs = mesh.vertices().len() * DIM;
        let mut springs = HashMap::new();
        let mut elements = Vec::with_capacity(mesh.indices().len());
        let mut positions = DVector::zeros(ndofs);

        for (i, pos) in positions.as_mut_slice().chunks_mut(DIM).enumerate() {
            pos.copy_from_slice(mesh.vertices()[i].coords.as_slice())
        }

        for idx in mesh.indices() {
            let idx = idx * DIM;
            let elt = MassSpringElement {
                handle: None,
                indices: idx,
                surface: N::zero(),
            };

            elements.push(elt);

            fn key(i: usize, j: usize) -> (usize, usize) {
                if i <= j {
                    (i, j)
                } else {
                    (j, i)
                }
            }

            let _ = springs.entry(key(idx.x, idx.y)).or_insert_with(|| {
                Spring::from_positions((idx.x, idx.y), positions.as_slice())
            });
            let _ = springs.entry(key(idx.y, idx.z)).or_insert_with(|| {
                Spring::from_positions((idx.y, idx.z), positions.as_slice())
            });
            let _ = springs.entry(key(idx.z, idx.x)).or_insert_with(|| {
                Spring::from_positions((idx.z, idx.x), positions.as_slice())
            });
        }

        MassSpringSurface {
            handle: None,
            springs: springs.values().cloned().collect(),
            elements,
            positions,
            velocities: DVector::zeros(ndofs),
            accelerations: DVector::zeros(ndofs),
            augmented_mass: DMatrix::zeros(ndofs, ndofs),
            inv_augmented_mass: LU::new(DMatrix::zeros(0, 0)),
            companion_id: 0,
            activation: ActivationStatus::new_active(),
            status: BodyStatus::Dynamic,
            stiffness,
            mass,
        }
    }

    /// Creates a rectangular-shaped quad.
    pub fn quad(transform: &Isometry<N>, extents: &Vector2<N>, nx: usize, ny: usize, mass: N, stiffness: N) -> Self {
        let mesh = procedural::quad(extents.x, extents.y, nx, ny);
        let vertices = mesh.coords.iter().map(|pt| transform * pt).collect();
        let indices = mesh.indices.unwrap_unified().into_iter().map(|tri| na::convert(tri)).collect();
        let trimesh = TriMesh::new(vertices, indices, None);
        Self::new(&trimesh, mass, stiffness)
    }

    /// The triangle mesh corresponding to this mass-spring-surface structural elements.
    pub fn mesh(&self) -> TriMesh<N> {
        let vertices = self.positions.as_slice().chunks(DIM).map(|pt| Point::from_coordinates(Vector::from_row_slice(pt))).collect();
        let indices = self.elements.iter().map(|elt| elt.indices / DIM).collect();

        TriMesh::new(vertices, indices, None)
    }

    fn update_gravity_force(&mut self, gravity: &Vector<N>) {
        let split_mass = self.mass / na::convert(self.elements.len() as f64);
        let gravity_force = gravity * split_mass;

        for i in 0..self.positions.len() / DIM {
            self.accelerations.fixed_rows_mut::<Dim>(i * DIM).copy_from(&gravity_force)
        }
    }

    fn update_augmented_mass_and_forces(&mut self, gravity: &Vector<N>, params: &IntegrationParameters<N>) {
        let split_mass = self.mass / na::convert((self.positions.len() / DIM) as f64);
        self.augmented_mass.fill_diagonal(split_mass);

//        for spring in self.springs {
//        }

        self.update_gravity_force(gravity);
        self.inv_augmented_mass = LU::new(self.augmented_mass.clone());
        assert!(self.inv_augmented_mass.solve_mut(&mut self.accelerations));
    }
}

impl<N: Real> Body<N> for MassSpringSurface<N> {
    fn update_kinematics(&mut self) {}

    fn update_dynamics(&mut self, gravity: &Vector<N>, params: &IntegrationParameters<N>) {
        self.update_augmented_mass_and_forces(gravity, params)
    }

    fn clear_dynamics(&mut self) {
        self.accelerations.fill(N::zero());
        self.augmented_mass.fill(N::zero());
    }

    fn apply_displacement(&mut self, disp: &[N]) {
        let disp = DVectorSlice::from_slice(disp, self.positions.len());
        self.positions += disp;
        println!("Applying displacement: {}", disp)
    }

    fn set_handle(&mut self, handle: Option<BodyHandle>) {
        self.handle = handle;

        for (i, element) in self.elements.iter_mut().enumerate() {
            element.handle = handle.map(|h| BodyPartHandle { body_handle: h, part_id: i })
        }
    }

    fn handle(&self) -> Option<BodyHandle> {
        self.handle
    }

    fn status(&self) -> BodyStatus {
        self.status
    }

    fn set_status(&mut self, status: BodyStatus) {
        self.status = status
    }

    fn activation_status(&self) -> &ActivationStatus<N> {
        &self.activation
    }

    fn set_deactivation_threshold(&mut self, threshold: Option<N>) {
        self.activation.set_deactivation_threshold(threshold)
    }

    fn ndofs(&self) -> usize {
        self.positions.len()
    }

    fn generalized_acceleration(&self) -> DVectorSlice<N> {
        DVectorSlice::from_slice(self.accelerations.as_slice(), self.accelerations.len())
    }

    fn generalized_velocity(&self) -> DVectorSlice<N> {
        DVectorSlice::from_slice(self.velocities.as_slice(), self.velocities.len())
    }

    fn companion_id(&self) -> usize {
        self.companion_id
    }

    fn set_companion_id(&mut self, id: usize) {
        self.companion_id = id
    }

    fn generalized_velocity_mut(&mut self) -> DVectorSliceMut<N> {
        let len = self.velocities.len();
        DVectorSliceMut::from_slice(self.velocities.as_mut_slice(), len)
    }

    fn integrate(&mut self, params: &IntegrationParameters<N>) {
        self.positions.axpy(params.dt, &self.velocities, N::one())
    }

    fn activate_with_energy(&mut self, energy: N) {
        self.activation.set_energy(energy)
    }

    fn deactivate(&mut self) {
        self.activation.set_energy(N::zero());
        self.velocities.fill(N::zero());
    }

    fn part(&self, handle: BodyPartHandle) -> &BodyPart<N> {
        &self.elements[handle.part_id]
    }

    fn part_mut(&mut self, handle: BodyPartHandle) -> &mut BodyPart<N> {
        &mut self.elements[handle.part_id]
    }

    fn contains_part(&self, handle: BodyPartHandle) -> bool {
        if let Some(me) = self.handle {
            handle.body_handle == me && handle.part_id < self.elements.len()
        } else {
            false
        }
    }

    fn deformed_positions(&self) -> Option<(DeformationsType, &[N])> {
        Some((DeformationsType::Vectors, self.positions.as_slice()))
    }

    fn deformed_positions_mut(&mut self) -> Option<(DeformationsType, &mut [N])> {
        Some((DeformationsType::Vectors, self.positions.as_mut_slice()))
    }

    fn inv_mass_mul_generalized_forces(&self, generalized_forces: &mut [N]) {
        let mut out = DVectorSliceMut::from_slice(generalized_forces, self.ndofs());
        assert!(self.inv_augmented_mass.solve_mut(&mut out))
    }

    fn body_part_jacobian_mul_unit_force(&self, part: &BodyPart<N>, pt: &Point<N>, force_dir: &ForceDirection<N>, out: &mut [N]) {
        if let ForceDirection::Linear(dir) = force_dir {
            let elt = part.downcast_ref::<MassSpringElement<N>>().expect("The provided body part must be a triangular mass-spring element");

            let a = self.positions.fixed_rows::<Dim>(elt.indices.x).into_owned();
            let b = self.positions.fixed_rows::<Dim>(elt.indices.y).into_owned();
            let c = self.positions.fixed_rows::<Dim>(elt.indices.z).into_owned();

            let tri = Triangle::new(
                Point::from_coordinates(a),
                Point::from_coordinates(b),
                Point::from_coordinates(c),
            );

            // XXX: This is extremely costly!
            let proj = tri.project_point_with_location(&Isometry::identity(), pt, false).1;
            let bcoords = proj.barycentric_coordinates().unwrap();

            VectorSliceMutN::<N, Dim>::from_slice(&mut out[elt.indices.x..]).copy_from(&(**dir * bcoords[0]));
            VectorSliceMutN::<N, Dim>::from_slice(&mut out[elt.indices.y..]).copy_from(&(**dir * bcoords[1]));
            VectorSliceMutN::<N, Dim>::from_slice(&mut out[elt.indices.z..]).copy_from(&(**dir * bcoords[2]));
        }
    }

    fn body_part_point_velocity(&self, part: &BodyPart<N>, point: &Point<N>, force_dir: &ForceDirection<N>) -> N {
        unimplemented!()
    }
}

impl<N: Real> BodyPart<N> for MassSpringElement<N> {
    fn handle(&self) -> Option<BodyPartHandle> {
        self.handle
    }

    fn center_of_mass(&self) -> Point<N> {
        unimplemented!()
    }

    fn position(&self) -> Isometry<N> {
        Isometry::identity() // XXX
    }

    fn velocity(&self) -> Velocity<N> {
        unimplemented!()
    }

    fn inertia(&self) -> Inertia<N> {
        unimplemented!()
    }

    fn local_inertia(&self) -> Inertia<N> {
        unimplemented!()
    }

    fn apply_force(&mut self, force: &Force<N>) {
        unimplemented!()
    }
}<commit_msg>Add explicit elastic terms.<commit_after>use std::ops::{AddAssign, SubAssign};
use std::iter;
use std::collections::HashMap;

use alga::linear::FiniteDimInnerSpace;
use na::{self, Real, DMatrix, DVector, DVectorSlice, DVectorSliceMut, VectorSliceMutN, LU, Dynamic, Vector2, Point3};
use ncollide::utils;
use ncollide::procedural::{self, IndexBuffer};
use ncollide::shape::{TriMesh, DeformationsType, TetrahedronPointLocation, Triangle};
use ncollide::query::PointQueryWithLocation;

use object::{Body, BodyPart, BodyHandle, BodyPartHandle, BodyStatus, ActivationStatus};
use solver::{IntegrationParameters, ForceDirection};
use math::{Force, Inertia, Velocity, Vector, Point, Isometry, DIM, Dim};

/// A triangular element of the mass-spring surface.
#[derive(Clone)]
pub struct MassSpringElement<N: Real> {
    handle: Option<BodyPartHandle>,
    indices: Point3<usize>,
    surface: N,
}

#[derive(Clone)]
struct Spring<N: Real> {
    elements: (usize, usize),
    rest_length: N,
}

impl<N: Real> Spring<N> {
    fn new(elements: (usize, usize), rest_length: N) -> Self {
        Spring {
            elements,
            rest_length,
        }
    }

    fn from_positions(elements: (usize, usize), positions: &[N]) -> Self {
        let p0 = Point::from_slice(&positions[elements.0..elements.0 + DIM]);
        let p1 = Point::from_slice(&positions[elements.1..elements.1 + DIM]);
        let rest_length = na::distance(&p0, &p1);

        Spring {
            elements,
            rest_length,
        }
    }
}

/// A deformable surface using a mass-spring model with triangular elements.
#[derive(Clone)]
pub struct MassSpringSurface<N: Real> {
    handle: Option<BodyHandle>,
    springs: Vec<Spring<N>>,
    elements: Vec<MassSpringElement<N>>,
    positions: DVector<N>,
    velocities: DVector<N>,
    accelerations: DVector<N>,
    augmented_mass: DMatrix<N>,
    inv_augmented_mass: LU<N, Dynamic, Dynamic>,

    companion_id: usize,
    activation: ActivationStatus<N>,
    status: BodyStatus,
    stiffness: N,
    mass: N,
    damping: N,
}

impl<N: Real> MassSpringSurface<N> {
    /// Creates a new deformable surface following the mass-spring model.
    ///
    /// The surface is initialized with a set of links corresponding to each trimesh edges.
    pub fn new(mesh: &TriMesh<N>, mass: N, stiffness: N, damping: N) -> Self {
        let ndofs = mesh.vertices().len() * DIM;
        let mut springs = HashMap::new();
        let mut elements = Vec::with_capacity(mesh.indices().len());
        let mut positions = DVector::zeros(ndofs);

        for (i, pos) in positions.as_mut_slice().chunks_mut(DIM).enumerate() {
            pos.copy_from_slice(mesh.vertices()[i].coords.as_slice())
        }

        for idx in mesh.indices() {
            let idx = idx * DIM;
            let elt = MassSpringElement {
                handle: None,
                indices: idx,
                surface: N::zero(),
            };

            elements.push(elt);

            fn key(i: usize, j: usize) -> (usize, usize) {
                if i <= j {
                    (i, j)
                } else {
                    (j, i)
                }
            }

            let _ = springs.entry(key(idx.x, idx.y)).or_insert_with(|| {
                Spring::from_positions((idx.x, idx.y), positions.as_slice())
            });
            let _ = springs.entry(key(idx.y, idx.z)).or_insert_with(|| {
                Spring::from_positions((idx.y, idx.z), positions.as_slice())
            });
            let _ = springs.entry(key(idx.z, idx.x)).or_insert_with(|| {
                Spring::from_positions((idx.z, idx.x), positions.as_slice())
            });
        }

        MassSpringSurface {
            handle: None,
            springs: springs.values().cloned().collect(),
            elements,
            positions,
            velocities: DVector::zeros(ndofs),
            accelerations: DVector::zeros(ndofs),
            augmented_mass: DMatrix::zeros(ndofs, ndofs),
            inv_augmented_mass: LU::new(DMatrix::zeros(0, 0)),
            companion_id: 0,
            activation: ActivationStatus::new_active(),
            status: BodyStatus::Dynamic,
            stiffness,
            mass,
            damping,
        }
    }

    /// Creates a rectangular-shaped quad.
    pub fn quad(transform: &Isometry<N>, extents: &Vector2<N>, nx: usize, ny: usize, mass: N, stiffness: N, damping: N) -> Self {
        let mesh = procedural::quad(extents.x, extents.y, nx, ny);
        let vertices = mesh.coords.iter().map(|pt| transform * pt).collect();
        let indices = mesh.indices.unwrap_unified().into_iter().map(|tri| na::convert(tri)).collect();
        let trimesh = TriMesh::new(vertices, indices, None);
        Self::new(&trimesh, mass, stiffness, damping)
    }

    /// The triangle mesh corresponding to this mass-spring-surface structural elements.
    pub fn mesh(&self) -> TriMesh<N> {
        let vertices = self.positions.as_slice().chunks(DIM).map(|pt| Point::from_coordinates(Vector::from_row_slice(pt))).collect();
        let indices = self.elements.iter().map(|elt| elt.indices / DIM).collect();

        TriMesh::new(vertices, indices, None)
    }

    fn update_gravity_force(&mut self, gravity: &Vector<N>) {
        let split_mass = self.mass / na::convert(self.elements.len() as f64);
        let gravity_force = gravity * split_mass;

        for i in 0..self.positions.len() / DIM {
            let mut acc = self.accelerations.fixed_rows_mut::<Dim>(i * DIM);
            acc += gravity_force
        }
    }

    fn update_augmented_mass_and_forces(&mut self, gravity: &Vector<N>, params: &IntegrationParameters<N>) {
        let split_mass = self.mass / na::convert((self.positions.len() / DIM) as f64);
        self.augmented_mass.fill_diagonal(split_mass);

        for spring in &self.springs {
            let p0 = self.positions.fixed_rows::<Dim>(spring.elements.0);
            let p1 = self.positions.fixed_rows::<Dim>(spring.elements.1);
            let v0 = self.velocities.fixed_rows::<Dim>(spring.elements.0);
            let v1 = self.velocities.fixed_rows::<Dim>(spring.elements.1);

            let ldot = v1 - v0;
            let mut l = p1 - p0;
            let length = l.norm();

            if length == N::zero() {
                l = Vector::y();
            } else {
                l /= length;
            }

            let f0 = l * (self.stiffness * (length - spring.rest_length) + self.damping * ldot.dot(&l));

            self.accelerations.fixed_rows_mut::<Dim>(spring.elements.0).add_assign(&f0);
            self.accelerations.fixed_rows_mut::<Dim>(spring.elements.1).sub_assign(&f0);
        }

        self.update_gravity_force(gravity);
        self.inv_augmented_mass = LU::new(self.augmented_mass.clone());
        assert!(self.inv_augmented_mass.solve_mut(&mut self.accelerations));
    }
}

impl<N: Real> Body<N> for MassSpringSurface<N> {
    fn update_kinematics(&mut self) {}

    fn update_dynamics(&mut self, gravity: &Vector<N>, params: &IntegrationParameters<N>) {
        self.update_augmented_mass_and_forces(gravity, params)
    }

    fn clear_dynamics(&mut self) {
        self.accelerations.fill(N::zero());
        self.augmented_mass.fill(N::zero());
    }

    fn apply_displacement(&mut self, disp: &[N]) {
        let disp = DVectorSlice::from_slice(disp, self.positions.len());
        self.positions += disp;
        println!("Applying displacement: {}", disp)
    }

    fn set_handle(&mut self, handle: Option<BodyHandle>) {
        self.handle = handle;

        for (i, element) in self.elements.iter_mut().enumerate() {
            element.handle = handle.map(|h| BodyPartHandle { body_handle: h, part_id: i })
        }
    }

    fn handle(&self) -> Option<BodyHandle> {
        self.handle
    }

    fn status(&self) -> BodyStatus {
        self.status
    }

    fn set_status(&mut self, status: BodyStatus) {
        self.status = status
    }

    fn activation_status(&self) -> &ActivationStatus<N> {
        &self.activation
    }

    fn set_deactivation_threshold(&mut self, threshold: Option<N>) {
        self.activation.set_deactivation_threshold(threshold)
    }

    fn ndofs(&self) -> usize {
        self.positions.len()
    }

    fn generalized_acceleration(&self) -> DVectorSlice<N> {
        DVectorSlice::from_slice(self.accelerations.as_slice(), self.accelerations.len())
    }

    fn generalized_velocity(&self) -> DVectorSlice<N> {
        DVectorSlice::from_slice(self.velocities.as_slice(), self.velocities.len())
    }

    fn companion_id(&self) -> usize {
        self.companion_id
    }

    fn set_companion_id(&mut self, id: usize) {
        self.companion_id = id
    }

    fn generalized_velocity_mut(&mut self) -> DVectorSliceMut<N> {
        let len = self.velocities.len();
        DVectorSliceMut::from_slice(self.velocities.as_mut_slice(), len)
    }

    fn integrate(&mut self, params: &IntegrationParameters<N>) {
        self.positions.axpy(params.dt, &self.velocities, N::one())
    }

    fn activate_with_energy(&mut self, energy: N) {
        self.activation.set_energy(energy)
    }

    fn deactivate(&mut self) {
        self.activation.set_energy(N::zero());
        self.velocities.fill(N::zero());
    }

    fn part(&self, handle: BodyPartHandle) -> &BodyPart<N> {
        &self.elements[handle.part_id]
    }

    fn part_mut(&mut self, handle: BodyPartHandle) -> &mut BodyPart<N> {
        &mut self.elements[handle.part_id]
    }

    fn contains_part(&self, handle: BodyPartHandle) -> bool {
        if let Some(me) = self.handle {
            handle.body_handle == me && handle.part_id < self.elements.len()
        } else {
            false
        }
    }

    fn deformed_positions(&self) -> Option<(DeformationsType, &[N])> {
        Some((DeformationsType::Vectors, self.positions.as_slice()))
    }

    fn deformed_positions_mut(&mut self) -> Option<(DeformationsType, &mut [N])> {
        Some((DeformationsType::Vectors, self.positions.as_mut_slice()))
    }

    fn inv_mass_mul_generalized_forces(&self, generalized_forces: &mut [N]) {
        let mut out = DVectorSliceMut::from_slice(generalized_forces, self.ndofs());
        assert!(self.inv_augmented_mass.solve_mut(&mut out))
    }

    fn body_part_jacobian_mul_unit_force(&self, part: &BodyPart<N>, pt: &Point<N>, force_dir: &ForceDirection<N>, out: &mut [N]) {
        if let ForceDirection::Linear(dir) = force_dir {
            let elt = part.downcast_ref::<MassSpringElement<N>>().expect("The provided body part must be a triangular mass-spring element");

            let a = self.positions.fixed_rows::<Dim>(elt.indices.x).into_owned();
            let b = self.positions.fixed_rows::<Dim>(elt.indices.y).into_owned();
            let c = self.positions.fixed_rows::<Dim>(elt.indices.z).into_owned();

            let tri = Triangle::new(
                Point::from_coordinates(a),
                Point::from_coordinates(b),
                Point::from_coordinates(c),
            );

            // XXX: This is extremely costly!
            let proj = tri.project_point_with_location(&Isometry::identity(), pt, false).1;
            let bcoords = proj.barycentric_coordinates().unwrap();

            VectorSliceMutN::<N, Dim>::from_slice(&mut out[elt.indices.x..]).copy_from(&(**dir * bcoords[0]));
            VectorSliceMutN::<N, Dim>::from_slice(&mut out[elt.indices.y..]).copy_from(&(**dir * bcoords[1]));
            VectorSliceMutN::<N, Dim>::from_slice(&mut out[elt.indices.z..]).copy_from(&(**dir * bcoords[2]));
        }
    }

    fn body_part_point_velocity(&self, part: &BodyPart<N>, point: &Point<N>, force_dir: &ForceDirection<N>) -> N {
        unimplemented!()
    }
}

impl<N: Real> BodyPart<N> for MassSpringElement<N> {
    fn handle(&self) -> Option<BodyPartHandle> {
        self.handle
    }

    fn center_of_mass(&self) -> Point<N> {
        unimplemented!()
    }

    fn position(&self) -> Isometry<N> {
        Isometry::identity() // XXX
    }

    fn velocity(&self) -> Velocity<N> {
        unimplemented!()
    }

    fn inertia(&self) -> Inertia<N> {
        unimplemented!()
    }

    fn local_inertia(&self) -> Inertia<N> {
        unimplemented!()
    }

    fn apply_force(&mut self, force: &Force<N>) {
        unimplemented!()
    }
}<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::{cell::RefCell, rc::Rc};

use dbus::{
    ffidisp::{
        stdintf::org_freedesktop_dbus::{
            ObjectManagerInterfacesAdded, ObjectManagerInterfacesRemoved,
        },
        BusType, Connection, ConnectionItem, NameFlag, WatchEvent,
    },
    message::SignalArgs,
    strings::Path,
    tree::{MTFn, Tree},
};

use crate::{
    dbus_api::{
        api::get_base_tree,
        blockdev::create_dbus_blockdev,
        consts,
        filesystem::create_dbus_filesystem,
        pool::create_dbus_pool,
        types::{DbusContext, DeferredAction, InterfacesAdded, InterfacesRemoved, TData},
    },
    engine::{Engine, Name, Pool, PoolUuid},
};

/// Returned data from when you connect a stratis engine to dbus.
pub struct DbusConnectionData {
    pub connection: Rc<RefCell<Connection>>,
    pub tree: Tree<MTFn<TData>, TData>,
    pub path: dbus::Path<'static>,
    pub context: DbusContext,
}

impl DbusConnectionData {
    /// Connect a stratis engine to dbus.
    pub fn connect(engine: Rc<RefCell<dyn Engine>>) -> Result<DbusConnectionData, dbus::Error> {
        let c = Connection::get_private(BusType::System)?;
        let (tree, object_path) = get_base_tree(DbusContext::new(engine));
        let dbus_context = tree.get_data().clone();
        tree.set_registered(&c, true)?;
        c.register_name(
            consts::STRATIS_BASE_SERVICE,
            NameFlag::ReplaceExisting as u32,
        )?;
        Ok(DbusConnectionData {
            connection: Rc::new(RefCell::new(c)),
            tree,
            path: object_path,
            context: dbus_context,
        })
    }

    /// Given the UUID of a pool, register all the pertinent information with dbus.
    pub fn register_pool(&mut self, pool_name: &Name, pool_uuid: PoolUuid, pool: &mut dyn Pool) {
        let pool_path =
            create_dbus_pool(&self.context, self.path.clone(), pool_name, pool_uuid, pool);
        for (fs_name, fs_uuid, fs) in pool.filesystems_mut() {
            create_dbus_filesystem(
                &self.context,
                pool_path.clone(),
                pool_name,
                &fs_name,
                fs_uuid,
                fs,
            );
        }
        for (uuid, tier, bd) in pool.blockdevs_mut() {
            create_dbus_blockdev(&self.context, pool_path.clone(), uuid, tier, bd);
        }

        self.process_deferred_actions()
    }

    /// Update the dbus tree with deferred adds and removes.
    fn process_deferred_actions(&mut self) {
        let mut actions = self.context.actions.borrow_mut();
        for action in actions.drain() {
            match action {
                DeferredAction::Add(path, interfaces) => {
                    let path_name = path.get_name().clone();
                    self.connection
                        .borrow_mut()
                        .register_object_path(&path_name)
                        .expect("Must succeed since object paths are unique");
                    self.tree.insert(path);
                    if let Err(e) = self.added_object_signal(path_name, interfaces) {
                        warn!("Failed to send a signal on D-Bus object addition: {}", e);
                    }
                }
                DeferredAction::Remove(path, interfaces) => {
                    self.connection.borrow_mut().unregister_object_path(&path);
                    self.tree.remove(&path);
                    if let Err(e) = self.removed_object_signal(path, interfaces) {
                        warn!("Failed to send a signal on D-Bus object removal: {}", e);
                    }
                }
            }
        }
    }

    /// Handle any client dbus requests
    pub fn handle(&mut self, fds: &[libc::pollfd]) {
        for pfd in fds.iter().filter(|pfd| pfd.revents != 0) {
            let items: Vec<ConnectionItem> = self
                .connection
                .borrow()
                .watch_handle(pfd.fd, WatchEvent::from_revents(pfd.revents))
                .collect();

            for item in items {
                if let ConnectionItem::MethodCall(ref msg) = item {
                    if let Some(v) = self.tree.handle(msg) {
                        // Probably the wisest is to ignore any send errors here -
                        // maybe the remote has disconnected during our processing.
                        for m in v {
                            let _ = self.connection.borrow_mut().send(m);
                        }
                    }

                    self.process_deferred_actions();
                }
            }
        }
    }

    /// Send an InterfacesAdded signal on the D-Bus
    pub fn added_object_signal(
        &self,
        object: Path<'static>,
        interfaces: InterfacesAdded,
    ) -> Result<(), dbus::Error> {
        self.connection
            .borrow()
            .send(
                ObjectManagerInterfacesAdded { object, interfaces }
                    .to_emit_message(&Path::from(consts::STRATIS_BASE_PATH)),
            )
            .map(|_| ())
            .map_err(|_| {
                dbus::Error::new_failed("Failed to send the requested signal on the D-Bus.")
            })
    }

    /// Send an InterfacesRemoved signal on the D-Bus
    pub fn removed_object_signal(
        &self,
        object: Path<'static>,
        interfaces: InterfacesRemoved,
    ) -> Result<(), dbus::Error> {
        self.connection
            .borrow()
            .send(
                ObjectManagerInterfacesRemoved { object, interfaces }
                    .to_emit_message(&Path::from(consts::STRATIS_BASE_PATH)),
            )
            .map(|_| ())
            .map_err(|_| {
                dbus::Error::new_failed("Failed to send the requested signal on the D-Bus.")
            })
    }
}
<commit_msg>Make private some helper methods<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::{cell::RefCell, rc::Rc};

use dbus::{
    ffidisp::{
        stdintf::org_freedesktop_dbus::{
            ObjectManagerInterfacesAdded, ObjectManagerInterfacesRemoved,
        },
        BusType, Connection, ConnectionItem, NameFlag, WatchEvent,
    },
    message::SignalArgs,
    strings::Path,
    tree::{MTFn, Tree},
};

use crate::{
    dbus_api::{
        api::get_base_tree,
        blockdev::create_dbus_blockdev,
        consts,
        filesystem::create_dbus_filesystem,
        pool::create_dbus_pool,
        types::{DbusContext, DeferredAction, InterfacesAdded, InterfacesRemoved, TData},
    },
    engine::{Engine, Name, Pool, PoolUuid},
};

/// Returned data from when you connect a stratis engine to dbus.
pub struct DbusConnectionData {
    pub connection: Rc<RefCell<Connection>>,
    pub tree: Tree<MTFn<TData>, TData>,
    pub path: dbus::Path<'static>,
    pub context: DbusContext,
}

impl DbusConnectionData {
    /// Connect a stratis engine to dbus.
    pub fn connect(engine: Rc<RefCell<dyn Engine>>) -> Result<DbusConnectionData, dbus::Error> {
        let c = Connection::get_private(BusType::System)?;
        let (tree, object_path) = get_base_tree(DbusContext::new(engine));
        let dbus_context = tree.get_data().clone();
        tree.set_registered(&c, true)?;
        c.register_name(
            consts::STRATIS_BASE_SERVICE,
            NameFlag::ReplaceExisting as u32,
        )?;
        Ok(DbusConnectionData {
            connection: Rc::new(RefCell::new(c)),
            tree,
            path: object_path,
            context: dbus_context,
        })
    }

    /// Given the UUID of a pool, register all the pertinent information with dbus.
    pub fn register_pool(&mut self, pool_name: &Name, pool_uuid: PoolUuid, pool: &mut dyn Pool) {
        let pool_path =
            create_dbus_pool(&self.context, self.path.clone(), pool_name, pool_uuid, pool);
        for (fs_name, fs_uuid, fs) in pool.filesystems_mut() {
            create_dbus_filesystem(
                &self.context,
                pool_path.clone(),
                pool_name,
                &fs_name,
                fs_uuid,
                fs,
            );
        }
        for (uuid, tier, bd) in pool.blockdevs_mut() {
            create_dbus_blockdev(&self.context, pool_path.clone(), uuid, tier, bd);
        }

        self.process_deferred_actions()
    }

    /// Update the dbus tree with deferred adds and removes.
    fn process_deferred_actions(&mut self) {
        let mut actions = self.context.actions.borrow_mut();
        for action in actions.drain() {
            match action {
                DeferredAction::Add(path, interfaces) => {
                    let path_name = path.get_name().clone();
                    self.connection
                        .borrow_mut()
                        .register_object_path(&path_name)
                        .expect("Must succeed since object paths are unique");
                    self.tree.insert(path);
                    if let Err(e) = self.added_object_signal(path_name, interfaces) {
                        warn!("Failed to send a signal on D-Bus object addition: {}", e);
                    }
                }
                DeferredAction::Remove(path, interfaces) => {
                    self.connection.borrow_mut().unregister_object_path(&path);
                    self.tree.remove(&path);
                    if let Err(e) = self.removed_object_signal(path, interfaces) {
                        warn!("Failed to send a signal on D-Bus object removal: {}", e);
                    }
                }
            }
        }
    }

    /// Handle any client dbus requests
    pub fn handle(&mut self, fds: &[libc::pollfd]) {
        for pfd in fds.iter().filter(|pfd| pfd.revents != 0) {
            let items: Vec<ConnectionItem> = self
                .connection
                .borrow()
                .watch_handle(pfd.fd, WatchEvent::from_revents(pfd.revents))
                .collect();

            for item in items {
                if let ConnectionItem::MethodCall(ref msg) = item {
                    if let Some(v) = self.tree.handle(msg) {
                        // Probably the wisest is to ignore any send errors here -
                        // maybe the remote has disconnected during our processing.
                        for m in v {
                            let _ = self.connection.borrow_mut().send(m);
                        }
                    }

                    self.process_deferred_actions();
                }
            }
        }
    }

    // Send an InterfacesAdded signal on the D-Bus
    fn added_object_signal(
        &self,
        object: Path<'static>,
        interfaces: InterfacesAdded,
    ) -> Result<(), dbus::Error> {
        self.connection
            .borrow()
            .send(
                ObjectManagerInterfacesAdded { object, interfaces }
                    .to_emit_message(&Path::from(consts::STRATIS_BASE_PATH)),
            )
            .map(|_| ())
            .map_err(|_| {
                dbus::Error::new_failed("Failed to send the requested signal on the D-Bus.")
            })
    }

    // Send an InterfacesRemoved signal on the D-Bus
    fn removed_object_signal(
        &self,
        object: Path<'static>,
        interfaces: InterfacesRemoved,
    ) -> Result<(), dbus::Error> {
        self.connection
            .borrow()
            .send(
                ObjectManagerInterfacesRemoved { object, interfaces }
                    .to_emit_message(&Path::from(consts::STRATIS_BASE_PATH)),
            )
            .map(|_| ())
            .map_err(|_| {
                dbus::Error::new_failed("Failed to send the requested signal on the D-Bus.")
            })
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_mut)]

extern crate regex;

#[macro_use]
extern crate lazy_static;

use regex::Regex;
use std::collections::HashMap;

/**
 * Stack value.
 */
enum SV {
    Undefined,
    {{{SV_ENUM}}}
}

/**
 * Lex rules.
 */
static LEX_RULES: {{{LEX_RULES}}};

/**
 * EOF value.
 */
static EOF: &'static str = "$";

/**
 * A macro for map literals.
 *
 * hashmap!{ 1 => "one", 2 => "two" };
 */
macro_rules! hashmap(
    { $($key:expr => $value:expr),+ } => {
        {
            let mut m = ::std::collections::HashMap::new();
            $(
                m.insert($key, $value);
            )+
            m
        }
     };
);

/**
 * Unwraps a SV for the result. The result type is known from the grammar.
 */
macro_rules! get_result {
    ($r:expr, $ty:ident) => (match $r { SV::$ty(v) => v, _ => unreachable!() });
}

/**
 * Pops a SV with needed enum value.
 */
macro_rules! pop {
    ($s:expr, $ty:ident) => (get_result!($s.pop().unwrap(), $ty));
}

/**
 * Productions data.
 *
 * 0 - encoded non-terminal, 1 - length of RHS to pop from the stack
 */
static PRODUCTIONS : {{{PRODUCTIONS}}};

/**
 * Table entry.
 */
enum TE {
    Accept,

    // Shift, and transit to the state.
    Shift(usize),

    // Reduce by a production number.
    Reduce(usize),

    // Simple state transition.
    Transit(usize),
}

lazy_static! {
    /**
     * Lexical rules grouped by lexer state (by start condition).
     */
    static ref LEX_RULES_BY_START_CONDITIONS: HashMap<&'static str, Vec<i32>> = {{{LEX_RULES_BY_START_CONDITIONS}}};

    /**
     * Maps a string name of a token type to its encoded number (the first
     * token number starts after all numbers for non-terminal).
     */
    static ref TOKENS_MAP: HashMap<&'static str, i32> = {{{TOKENS}}};

    /**
     * Parsing table.
     *
     * Vector index is the state number, value is a map
     * from an encoded symbol to table entry (TE).
     */
    static ref TABLE: Vec<HashMap<i32, TE>>= {{{TABLE}}};
}

// ------------------------------------
// Module include prologue.
//
// Should include at least result type:
//
// type TResult = <...>;
//
// Can also include parsing hooks:
//
//   fn on_parse_begin(parser: &mut Parser, string: &'static str) {
//     ...
//   }
//
//   fn on_parse_begin(parser: &mut Parser, string: &'static str) {
//     ...
//   }
//

{{{MODULE_INCLUDE}}}

// ---  end of Module include ---------

{{{TOKENIZER}}}

// ------------------------------------------------------------------
// Parser.

/**
 * Parser.
 */
pub struct Parser {
    /**
     * Parsing stack: semantic values.
     */
    values_stack: Vec<SV>,

    /**
     * Parsing stack: state numbers.
     */
    states_stack: Vec<usize>,

    /**
     * Tokenizer instance.
     */
    tokenizer: Tokenizer,

    /**
     * Semantic action handlers.
     */
    handlers: [fn(&mut Parser) -> SV; {{{PRODUCTION_HANDLERS_COUNT}}}],
}

impl Parser {
    /**
     * Creates a new Parser instance.
     */
    pub fn new() -> Parser {
        Parser {
            // Stacks.
            values_stack: Vec::new(),
            states_stack: Vec::new(),

            tokenizer: Tokenizer::new(),

            handlers: {{{PRODUCTION_HANDLERS_ARRAY}}}
        }
    }

    /**
     * Parses a string.
     */
    pub fn parse(&mut self, string: &'static str) -> TResult {
        {{{ON_PARSE_BEGIN_CALL}}}

        // Initialize the tokenizer and the string.
        self.tokenizer.init_string(string);

        // Initialize the stacks.
        self.values_stack.clear();

        // Initial 0 state.
        self.states_stack.clear();
        self.states_stack.push(0);

        let mut token = self.tokenizer.get_next_token();
        let mut shifted_token = token;

        loop {
            let state = *self.states_stack.last().unwrap();
            let column = token.kind;

            if !TABLE[state].contains_key(&column) {
                self.unexpected_token(&token);
                break;
            }

            let entry = &TABLE[state][&column];

            match entry {

                // Shift a token, go to state.
                &TE::Shift(next_state) => {
                    // Push token.
                    self.values_stack.push(SV::_0(token));

                    // Push next state number: "s5" -> 5
                    self.states_stack.push(next_state as usize);

                    shifted_token = token;
                    token = self.tokenizer.get_next_token();
                },

                // Reduce by production.
                &TE::Reduce(production_number) => {
                    let production = PRODUCTIONS[production_number];

                    self.tokenizer.yytext = shifted_token.value;
                    self.tokenizer.yyleng = shifted_token.value.len();

                    let mut rhs_length = production[1];
                    while rhs_length > 0 {
                        self.states_stack.pop();
                        rhs_length = rhs_length - 1;
                    }

                    // Call the handler, push result onto the stack.
                    let result_value = self.handlers[production_number](self);

                    let previous_state = *self.states_stack.last().unwrap();
                    let symbol_to_reduce_with = production[0];

                    // Then push LHS onto the stack.
                    self.values_stack.push(result_value);

                    let next_state = match &TABLE[previous_state][&symbol_to_reduce_with] {
                        &TE::Transit(next_state) => next_state,
                        _ => unreachable!(),
                    };

                    self.states_stack.push(next_state);
                },

                // Accept the string.
                &TE::Accept => {
                    // Pop state number.
                    self.states_stack.pop();

                    // Pop the parsed value.
                    let parsed = self.values_stack.pop().unwrap();

                    if self.states_stack.len() != 1 ||
                        self.states_stack.pop().unwrap() != 0 ||
                        self.tokenizer.has_more_tokens() {
                        self.unexpected_token(&token);
                    }

                    let result = get_result!(parsed, {{{RESULT_TYPE}}});
                    {{{ON_PARSE_END_CALL}}}
                    return result;
                },

                _ => unreachable!(),
            }
        }

        unreachable!();
    }

    fn unexpected_token(&mut self, token: &Token) {
        {{{ON_PARSE_ERROR_CALL}}}
    }

    {{{PRODUCTION_HANDLERS}}}
}
<commit_msg>rust-plugin: allow unreachable_code<commit_after>#![allow(dead_code)]
#![allow(unused_mut)]
#![allow(unreachable_code)]

extern crate regex;

#[macro_use]
extern crate lazy_static;

use regex::Regex;
use std::collections::HashMap;

/**
 * Stack value.
 */
enum SV {
    Undefined,
    {{{SV_ENUM}}}
}

/**
 * Lex rules.
 */
static LEX_RULES: {{{LEX_RULES}}};

/**
 * EOF value.
 */
static EOF: &'static str = "$";

/**
 * A macro for map literals.
 *
 * hashmap!{ 1 => "one", 2 => "two" };
 */
macro_rules! hashmap(
    { $($key:expr => $value:expr),+ } => {
        {
            let mut m = ::std::collections::HashMap::new();
            $(
                m.insert($key, $value);
            )+
            m
        }
     };
);

/**
 * Unwraps a SV for the result. The result type is known from the grammar.
 */
macro_rules! get_result {
    ($r:expr, $ty:ident) => (match $r { SV::$ty(v) => v, _ => unreachable!() });
}

/**
 * Pops a SV with needed enum value.
 */
macro_rules! pop {
    ($s:expr, $ty:ident) => (get_result!($s.pop().unwrap(), $ty));
}

/**
 * Productions data.
 *
 * 0 - encoded non-terminal, 1 - length of RHS to pop from the stack
 */
static PRODUCTIONS : {{{PRODUCTIONS}}};

/**
 * Table entry.
 */
enum TE {
    Accept,

    // Shift, and transit to the state.
    Shift(usize),

    // Reduce by a production number.
    Reduce(usize),

    // Simple state transition.
    Transit(usize),
}

lazy_static! {
    /**
     * Lexical rules grouped by lexer state (by start condition).
     */
    static ref LEX_RULES_BY_START_CONDITIONS: HashMap<&'static str, Vec<i32>> = {{{LEX_RULES_BY_START_CONDITIONS}}};

    /**
     * Maps a string name of a token type to its encoded number (the first
     * token number starts after all numbers for non-terminal).
     */
    static ref TOKENS_MAP: HashMap<&'static str, i32> = {{{TOKENS}}};

    /**
     * Parsing table.
     *
     * Vector index is the state number, value is a map
     * from an encoded symbol to table entry (TE).
     */
    static ref TABLE: Vec<HashMap<i32, TE>>= {{{TABLE}}};
}

// ------------------------------------
// Module include prologue.
//
// Should include at least result type:
//
// type TResult = <...>;
//
// Can also include parsing hooks:
//
//   fn on_parse_begin(parser: &mut Parser, string: &'static str) {
//     ...
//   }
//
//   fn on_parse_begin(parser: &mut Parser, string: &'static str) {
//     ...
//   }
//

{{{MODULE_INCLUDE}}}

// ---  end of Module include ---------

{{{TOKENIZER}}}

// ------------------------------------------------------------------
// Parser.

/**
 * Parser.
 */
pub struct Parser {
    /**
     * Parsing stack: semantic values.
     */
    values_stack: Vec<SV>,

    /**
     * Parsing stack: state numbers.
     */
    states_stack: Vec<usize>,

    /**
     * Tokenizer instance.
     */
    tokenizer: Tokenizer,

    /**
     * Semantic action handlers.
     */
    handlers: [fn(&mut Parser) -> SV; {{{PRODUCTION_HANDLERS_COUNT}}}],
}

impl Parser {
    /**
     * Creates a new Parser instance.
     */
    pub fn new() -> Parser {
        Parser {
            // Stacks.
            values_stack: Vec::new(),
            states_stack: Vec::new(),

            tokenizer: Tokenizer::new(),

            handlers: {{{PRODUCTION_HANDLERS_ARRAY}}}
        }
    }

    /**
     * Parses a string.
     */
    pub fn parse(&mut self, string: &'static str) -> TResult {
        {{{ON_PARSE_BEGIN_CALL}}}

        // Initialize the tokenizer and the string.
        self.tokenizer.init_string(string);

        // Initialize the stacks.
        self.values_stack.clear();

        // Initial 0 state.
        self.states_stack.clear();
        self.states_stack.push(0);

        let mut token = self.tokenizer.get_next_token();
        let mut shifted_token = token;

        loop {
            let state = *self.states_stack.last().unwrap();
            let column = token.kind;

            if !TABLE[state].contains_key(&column) {
                self.unexpected_token(&token);
                break;
            }

            let entry = &TABLE[state][&column];

            match entry {

                // Shift a token, go to state.
                &TE::Shift(next_state) => {
                    // Push token.
                    self.values_stack.push(SV::_0(token));

                    // Push next state number: "s5" -> 5
                    self.states_stack.push(next_state as usize);

                    shifted_token = token;
                    token = self.tokenizer.get_next_token();
                },

                // Reduce by production.
                &TE::Reduce(production_number) => {
                    let production = PRODUCTIONS[production_number];

                    self.tokenizer.yytext = shifted_token.value;
                    self.tokenizer.yyleng = shifted_token.value.len();

                    let mut rhs_length = production[1];
                    while rhs_length > 0 {
                        self.states_stack.pop();
                        rhs_length = rhs_length - 1;
                    }

                    // Call the handler, push result onto the stack.
                    let result_value = self.handlers[production_number](self);

                    let previous_state = *self.states_stack.last().unwrap();
                    let symbol_to_reduce_with = production[0];

                    // Then push LHS onto the stack.
                    self.values_stack.push(result_value);

                    let next_state = match &TABLE[previous_state][&symbol_to_reduce_with] {
                        &TE::Transit(next_state) => next_state,
                        _ => unreachable!(),
                    };

                    self.states_stack.push(next_state);
                },

                // Accept the string.
                &TE::Accept => {
                    // Pop state number.
                    self.states_stack.pop();

                    // Pop the parsed value.
                    let parsed = self.values_stack.pop().unwrap();

                    if self.states_stack.len() != 1 ||
                        self.states_stack.pop().unwrap() != 0 ||
                        self.tokenizer.has_more_tokens() {
                        self.unexpected_token(&token);
                    }

                    let result = get_result!(parsed, {{{RESULT_TYPE}}});
                    {{{ON_PARSE_END_CALL}}}
                    return result;
                },

                _ => unreachable!(),
            }
        }

        unreachable!();
    }

    fn unexpected_token(&mut self, token: &Token) {
        {{{ON_PARSE_ERROR_CALL}}}
    }

    {{{PRODUCTION_HANDLERS}}}
}
<|endoftext|>


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

// ignore-msvc -- sprintf isn't a symbol in msvcrt? maybe a #define?

#![feature(libc, std_misc)]

extern crate libc;

use std::ffi::{CStr, CString};
use libc::{c_char, c_int};

extern {
    fn sprintf(s: *mut c_char, format: *const c_char, ...) -> c_int;
}

unsafe fn check<T, F>(expected: &str, f: F) where F: FnOnce(*mut c_char) -> T {
    let mut x = [0 as c_char; 50];
    f(&mut x[0] as *mut c_char);
    assert_eq!(expected.as_bytes(), CStr::from_ptr(x.as_ptr()).to_bytes());
}

pub fn main() {

    unsafe {
        // Call with just the named parameter
        let c = CString::new(&b"Hello World\n"[..]).unwrap();
        check("Hello World\n", |s| sprintf(s, c.as_ptr()));

        // Call with variable number of arguments
        let c = CString::new(&b"%d %f %c %s\n"[..]).unwrap();
        check("42 42.500000 a %d %f %c %s\n\n", |s| {
            sprintf(s, c.as_ptr(), 42, 42.5f64, 'a' as c_int, c.as_ptr());
        });

        // Make a function pointer
        let x: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int = sprintf;

        // A function that takes a function pointer
        unsafe fn call(fp: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int) {
            // Call with just the named parameter
            let c = CString::new(&b"Hello World\n"[..]).unwrap();
            check("Hello World\n", |s| fp(s, c.as_ptr()));

            // Call with variable number of arguments
            let c = CString::new(&b"%d %f %c %s\n"[..]).unwrap();
            check("42 42.500000 a %d %f %c %s\n\n", |s| {
                fp(s, c.as_ptr(), 42, 42.5f64, 'a' as c_int, c.as_ptr());
            });
        }

        // Pass sprintf directly
        call(sprintf);

        // Pass sprintf indirectly
        call(x);
    }

}
<commit_msg>Auto merge of #33894 - nagisa:windows-lack-endurance-for-sprint, r=alexcrichton<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[link(name = "rust_test_helpers")]
extern {
    fn rust_interesting_average(_: u64, ...) -> f64;
}

pub fn main() {
    // Call without variadic arguments
    unsafe {
        assert!(rust_interesting_average(0).is_nan());
    }

    // Call with direct arguments
    unsafe {
        assert_eq!(rust_interesting_average(1, 10i64, 10.0f64) as i64, 20);
    }

    // Call with named arguments, variable number of them
    let (x1, x2, x3, x4) = (10i64, 10.0f64, 20i64, 20.0f64);
    unsafe {
        assert_eq!(rust_interesting_average(2, x1, x2, x3, x4) as i64, 30);
    }

    // A function that takes a function pointer
    unsafe fn call(fp: unsafe extern fn(u64, ...) -> f64) {
        let (x1, x2, x3, x4) = (10i64, 10.0f64, 20i64, 20.0f64);
        assert_eq!(fp(2, x1, x2, x3, x4) as i64, 30);
    }

    unsafe {
        call(rust_interesting_average);

        // Make a function pointer, pass indirectly
        let x: unsafe extern fn(u64, ...) -> f64 = rust_interesting_average;
        call(x);
    }
}
<|endoftext|>


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

use std::fs::File;
use std::io::BufWriter;
use std::io::prelude::Write;

/*================================================================================================*/
/*------ENUMS-------------------------------------------------------------------------------------*/
/*================================================================================================*/

/// The log level enum
///
/// It is used with the logger struct, and is used to determine the severity of the message.
pub enum LogLevel {

    /// Used for logging debug messages (stripped out of release builds)
    Debug   (String),
    /// Used for normal logging messages
    Message (String),
    /// Used for warnings (non critical errors)
    Warning (String),
    /// Used for critical errors
    Error   (String)
}

/*================================================================================================*/
/*------STRUCTS-----------------------------------------------------------------------------------*/
/*================================================================================================*/

/// The logger struct.
///
/// It allows for basic logging capabilities.
/// It can currently log strings, but others will be added in the future.
pub struct Logger {

    // Private
    log_file    : Option <BufWriter <File>>,
    is_enabled  : bool,
    is_logging  : bool
}

/*================================================================================================*/
/*------PUBLIC STATIC FUNCTIONS-------------------------------------------------------------------*/
/*================================================================================================*/

impl Logger {

    /// Creates a new logger instance
    ///
    /// Logging is disabled on faliure.
    pub fn new (log_file_path : String) -> Logger {

        match File::create (&log_file_path) {

            Ok (file) => Logger {log_file   : Some (BufWriter::new (file)),
                                 is_enabled : true,
                                 is_logging : false},

            Err (_) => {

                println! ("WARNING: Log file could not be created\n
                           Logging has been disabled");

                Logger {log_file   : None,
                        is_enabled : false,
                        is_logging : false}
            }
        }
    }

/*================================================================================================*/
/*------PUBLIC FUNCTIONS--------------------------------------------------------------------------*/
/*================================================================================================*/

    /// Starts file logging
    // TODO: Write begin log string
    pub fn begin_log (&mut self) {

        self.is_logging = true;
    }

/*================================================================================================*/

    /// Logs a message
    // TODO : Add log level specific messages (ie: DEBUG: "Insert message here")
    pub fn log (&mut self, log_level : LogLevel) {

        // Check if logger is enabled and logging
        if self.is_enabled && self.is_logging {

            // Get the buffer from the logger struct
            let buffer = self.log_file.as_mut ().unwrap ();

            match log_level {

                // Debug
                LogLevel::Debug (m) => {

                    // Only call if run in debug
                    if cfg! (debug_assertions) {

                        buffer.write (m.as_bytes ()).unwrap ();
                    }
                },

                // Message
                LogLevel::Message (m) => {

                    buffer.write (m.as_bytes ()).unwrap ();
                },

                // Warning
                LogLevel::Warning (m) => {

                    buffer.write (m.as_bytes ()).unwrap ();
                },

                // Error
                LogLevel::Error (m) => {

                    buffer.write (m.as_bytes ()).unwrap ();
                }
            }
        }
    }

/*================================================================================================*/

    /// Stops file logging
    // TODO: Write end log string
    pub fn end_log (&mut self) {

        self.is_logging = false;
    }
}
<commit_msg>Added examples to documentation<commit_after>/*================================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*================================================================================================*/

use std::fs::File;
use std::io::BufWriter;
use std::io::prelude::Write;

/*================================================================================================*/
/*------ENUMS-------------------------------------------------------------------------------------*/
/*================================================================================================*/

/// The log level enum
///
/// It is used with the logger struct, and is used to determine the severity of the message.
pub enum LogLevel {

    /// Used for logging debug messages (stripped out of release builds)
    Debug   (String),
    /// Used for normal logging messages
    Message (String),
    /// Used for warnings (non critical errors)
    Warning (String),
    /// Used for critical errors
    Error   (String)
}

/*================================================================================================*/
/*------STRUCTS-----------------------------------------------------------------------------------*/
/*================================================================================================*/

/// The logger struct.
///
/// It allows for basic logging capabilities.
/// It can currently log strings, but others will be added in the future.
pub struct Logger {

    // Private
    log_file    : Option <BufWriter <File>>,
    is_enabled  : bool,
    is_logging  : bool
}

/*================================================================================================*/
/*------PUBLIC STATIC FUNCTIONS-------------------------------------------------------------------*/
/*================================================================================================*/

impl Logger {

    /// Creates a new logger instance
    ///
    /// Logging is disabled on faliure.
    ///
    /// # Examples
    /// ```
    /// let logger = Logger::new ("log.txt".to_string ());
    pub fn new (log_file_path : String) -> Logger {

        match File::create (&log_file_path) {

            Ok (file) => Logger {log_file   : Some (BufWriter::new (file)),
                                 is_enabled : true,
                                 is_logging : false},

            Err (_) => {

                println! ("WARNING: Log file could not be created\n
                           Logging has been disabled");

                Logger {log_file   : None,
                        is_enabled : false,
                        is_logging : false}
            }
        }
    }

/*================================================================================================*/
/*------PUBLIC FUNCTIONS--------------------------------------------------------------------------*/
/*================================================================================================*/

    /// Starts file logging
    // TODO: Write begin log string
    pub fn begin_log (&mut self) {

        self.is_logging = true;
    }

/*================================================================================================*/

    /// Logs a message
    ///
    /// # Examples
    /// ```
    /// let logger = Logger::new ("log.txt".to_string ());
    ///
    /// logger.log (LogLevel::Debug   ("This is a log entry".to_string ())) // Debug
    /// logger.log (LogLevel::Message ("This is a log entry".to_string ())) // Message
    /// logger.log (LogLevel::Warning ("This is a log entry".to_string ())) // Warning
    /// logger.log (LogLevel::Error   ("This is a log entry".to_string ())) // Error
    // TODO : Add log level specific messages (ie: DEBUG: "Insert message here")
    pub fn log (&mut self, log_level : LogLevel) {

        // Check if logger is enabled and logging
        if self.is_enabled && self.is_logging {

            // Get the buffer from the logger struct
            let buffer = self.log_file.as_mut ().unwrap ();

            match log_level {

                // Debug
                LogLevel::Debug (m) => {

                    // Only call if run in debug
                    if cfg! (debug_assertions) {

                        buffer.write (m.as_bytes ()).unwrap ();
                    }
                },

                // Message
                LogLevel::Message (m) => {

                    buffer.write (m.as_bytes ()).unwrap ();
                },

                // Warning
                LogLevel::Warning (m) => {

                    buffer.write (m.as_bytes ()).unwrap ();
                },

                // Error
                LogLevel::Error (m) => {

                    buffer.write (m.as_bytes ()).unwrap ();
                }
            }
        }
    }

/*================================================================================================*/

    /// Stops file logging
    // TODO: Write end log string
    pub fn end_log (&mut self) {

        self.is_logging = false;
    }
}
<|endoftext|>