<commit_before>use regex::Regex;
use std::path::PathBuf;
use std::result::Result;
use subprocess::{Exec, ExitStatus, Redirection};

const LOOP_BACKING_DEVICE_BASENAME: &'static str = "flaglock6-home";
const LOOP_DEVICE_PARTITION_LABEL: &'static str = "fl6";
const RSYNC_DOT_NET_REMOTE_DIR: &'static str = "usw-s007.rsync.net:./";

const RUN_MEDIA_KALVIN: &'static str = "/run/media/kalvin";

#[derive(Debug)]
pub enum AuricError {
    Invocation(String),
    Io(String),
    Subprocess(String),
    NotFound,
}

enum AuricOperationMode {
    Mount,
    Unmount,
    Rsync,
}

impl From<subprocess::PopenError> for AuricError {
    fn from(err: subprocess::PopenError) -> AuricError {
        AuricError::Subprocess(err.to_string())
    }
}

struct SshfsManager {
    mountpoint: PathBuf,
}

struct LoopManager {
    target: Regex,
    backing: PathBuf,
}

struct LuksManager {
    device: PathBuf,
}

struct AuricImpl {
    sshfs_manager: SshfsManager,
    loop_manager: LoopManager,
    luks_manager: LuksManager,
}

fn exec_with_stdout(command: &str, args: &[&str], error_hint: &str) -> Result<String, AuricError> {
    let result = Exec::cmd(command)
        .args(args)
        .stdout(Redirection::Pipe)
        .stderr(Redirection::Pipe)
        .capture()?;
    if !result.success() {
        return Err(AuricError::Subprocess(format!(
            "{} failed: ``{}''",
            error_hint,
            result.stderr_str(),
        )));
    }
    Ok(result.stdout_str())
}

fn exec(command: &str, args: &[&str], error_hint: &str) -> Result<(), AuricError> {
    exec_with_stdout(command, args, error_hint).map(|_stdout_str| ())
}

fn exec_rsync(args: &[&str]) -> Result<(), AuricError> {
    let result = Exec::cmd("rsync").args(args).join()?;
    if !result.success() {
        match result {
            ExitStatus::Exited(code) => {
                return Err(AuricError::Subprocess(format!(
                    "rsync exited with code {}",
                    code
                )))
            }
            ExitStatus::Signaled(signum) => {
                return Err(AuricError::Subprocess(format!(
                    "rsync exited with signal {}",
                    signum
                )))
            }
            ExitStatus::Other(code) => {
                return Err(AuricError::Subprocess(format!(
                    "unknown rsync error: {}",
                    code
                )))
            }
            ExitStatus::Undetermined => {
                return Err(AuricError::Subprocess("unknown rsync error!".to_string()))
            }
        }
    }
    Ok(())
}

impl SshfsManager {
    pub fn new() -> Result<SshfsManager, AuricError> {
        let xdg_runtime_dir = match std::env::var("XDG_RUNTIME_DIR") {
            Ok(val) => val,
            Err(e) => {
                return Err(AuricError::Invocation(format!(
                    "fatal error getting ${{XDG_RUNTIME_DIR}}: ``{}''",
                    e
                )))
            }
        };
        let mut mountpoint = PathBuf::new();
        mountpoint.push(xdg_runtime_dir);
        mountpoint.push("rsync.net-mountpoint");

        Ok(SshfsManager {
            mountpoint: mountpoint,
        })
    }

    fn ensure_mountpoint_is_dir(&self) -> Result<(), AuricError> {
        if self.mountpoint.is_dir() {
            return Ok(());
        }
        std::fs::create_dir(self.mountpoint.as_path())
            .map_err(|e| AuricError::Io(format!("bad mountpoint: ``{}''", e)))
    }

    // Does _not_ ensure that backing device exists.
    pub fn loop_backing_device_path(&self) -> PathBuf {
        let mut result: PathBuf = self.mountpoint.clone();
        result.push(LOOP_BACKING_DEVICE_BASENAME);
        result
    }

    fn loop_backing_device_present(&self) -> bool {
        self.loop_backing_device_path().is_file()
    }

    pub fn mount(&self) -> Result<(), AuricError> {
        self.ensure_mountpoint_is_dir()?;
        if self.loop_backing_device_present() {
            return Ok(());
        }

        // Invoke `sshfs`
        // *    with compression,
        // *    allowing other users to access the mounted filesystem
        //      (necessary to allow loop-mounts), and
        // *    attempting to reconnect if we lose the connection.
        exec(
            "sshfs",
            &[
                "-C",
                "-o",
                "allow_other,reconnect",
                RSYNC_DOT_NET_REMOTE_DIR,
                self.mountpoint.to_str().unwrap(),
            ],
            "sshfs mount",
        )
    }

    pub fn unmount(&self) -> Result<(), AuricError> {
        if !self.loop_backing_device_present() {
            return Ok(());
        }
        exec(
            "fusermount",
            &["-u", self.mountpoint.to_str().unwrap()],
            "fusermount -u",
        )
    }
}

impl LoopManager {
    pub fn new(backing: &PathBuf) -> LoopManager {
        let target = format!(
            r"^(/dev/loop\d)(\s+\d+){{4}}\s+({})\s+",
            backing.to_str().unwrap()
        );
        LoopManager {
            target: Regex::new(&target).unwrap(),
            backing: backing.clone(),
        }
    }

    pub fn find(&self) -> Result<PathBuf, AuricError> {
        let losetup_stdout = exec_with_stdout("losetup", &["-l"], "loop device enumeration")?;
        for line in losetup_stdout.lines() {
            if let Some(captures) = self.target.captures(line) {
                return Ok(PathBuf::from(captures.get(1).unwrap().as_str()));
            }
        }
        Err(AuricError::NotFound)
    }

    pub fn attach(&self) -> Result<(), AuricError> {
        if let Ok(_attached_loop) = self.find() {
            return Ok(());
        }

        exec(
            "udisksctl",
            &["loop-setup", "-f", self.backing.to_str().unwrap()],
            "loop device attach",
        )
    }

    // Note that the loop device will linger if the volume remains
    // unlocked. Prefer not to call this before locking.
    pub fn detach(&self) -> Result<(), AuricError> {
        let attached_loop = match self.find() {
            Ok(path) => path,
            Err(e) => {
                if let AuricError::NotFound = e {
                    return Ok(());
                }
                return Err(e);
            }
        };
        exec(
            "udisksctl",
            &["loop-delete", "-b", attached_loop.to_str().unwrap()],
            "loop device detach",
        )
    }
}

impl LuksManager {
    pub fn new() -> LuksManager {
        let mut device = PathBuf::from("/dev/disk/by-label");
        device.push(LOOP_DEVICE_PARTITION_LABEL);
        LuksManager { device: device }
    }

    pub fn unlock(&self, locked_device: &PathBuf) -> Result<(), AuricError> {
        exec(
            "udisksctl",
            &["unlock", "-b", locked_device.to_str().unwrap()],
            format!("unlocking {}", locked_device.to_str().unwrap()).as_str(),
        )
    }

    pub fn lock(&self, underlying_device: &PathBuf) -> Result<(), AuricError> {
        exec(
            "udisksctl",
            &["lock", "-b", underlying_device.to_str().unwrap()],
            format!("locking {}", underlying_device.to_str().unwrap()).as_str(),
        )
    }

    pub fn mount(&self) -> Result<(), AuricError> {
        exec(
            "udisksctl",
            &["mount", "-b", self.device.to_str().unwrap()],
            format!("mounting {}", self.device.to_str().unwrap()).as_str(),
        )
    }

    pub fn unmount(&self) -> Result<(), AuricError> {
        exec(
            "udisksctl",
            &["unmount", "-b", self.device.to_str().unwrap()],
            format!("unmounting {}", self.device.to_str().unwrap()).as_str(),
        )
    }
}

fn get_action() -> Result<AuricOperationMode, AuricError> {
    let mut args_iter = std::env::args();
    args_iter.next();
    if let Some(action) = args_iter.next() {
        match action.as_str() {
            "mount" => return Ok(AuricOperationMode::Mount),
            "unmount" => return Ok(AuricOperationMode::Unmount),
            "rsync" => return Ok(AuricOperationMode::Rsync),
            _ => {
                return Err(AuricError::Invocation(format!(
                    "unknown action: ``{}''",
                    action
                )))
            }
        }
    }
    Err(AuricError::Invocation("no action given".to_string()))
}

impl AuricImpl {
    pub fn new() -> Result<AuricImpl, AuricError> {
        let sshfs_manager = SshfsManager::new()?;
        let loop_backing_device_path = sshfs_manager.loop_backing_device_path();
        Ok(AuricImpl {
            sshfs_manager: sshfs_manager,
            loop_manager: LoopManager::new(&loop_backing_device_path),
            luks_manager: LuksManager::new(),
        })
    }

    fn mount(&self) -> Result<(), AuricError> {
        println!("{}", "Mounting sshfs...");
        self.sshfs_manager.mount()?;
        println!("{}", "Attaching loop device...");
        self.loop_manager.attach()?;
        println!("{}", "Finding newly attached loop device...");
        let loop_device = self.loop_manager.find()?;
        println!("{}", "Unlocking volume...");
        self.luks_manager.unlock(&loop_device)?;
        println!("{}", "Mounting volume...");
        self.luks_manager.mount()
    }

    fn unmount(&self) -> Result<(), AuricError> {
        println!("{}", "Unmounting volume...");
        self.luks_manager.unmount()?;
        println!("{}", "Finding backing loop device...");
        let loop_device = self.loop_manager.find()?;
        println!("{}", "Locking volume...");
        self.luks_manager.lock(&loop_device)?;
        println!("{}", "Detaching loop device...");
        self.loop_manager.detach()?;
        println!("{}", "Unmounting sshfs...");
        self.sshfs_manager.unmount()
    }

    fn rsync(&self) -> Result<(), AuricError> {
        // I'm not pulling in the `home_dir` crate just to grab a value
        // that I suspect will be immutable for many years to come.
        // Likewise, the user mount directory is lazily hardcoded.
        let mut remote_directory = PathBuf::from(RUN_MEDIA_KALVIN);
        remote_directory.push(LOOP_DEVICE_PARTITION_LABEL);
        if !remote_directory.is_dir() {
            return Err(AuricError::Invocation(format!(
                "remote directory ``{}'' not mounted",
                remote_directory.display()
            )));
        }

        exec_rsync(&[
            "--delete",
            "-avPS",
            "--exclude=/.cache/",
            "--exclude=/.cargo/",
            "--exclude=/.local/share/",
            "--exclude=/.mozilla/",
            "--exclude=/.thunderbird/",
            "--exclude=/Downloads/.firefox-nightly/",
            "--exclude=/Downloads/.thunderbird-beta/",
            "--delete-excluded",
            "/home/kalvin/",
            remote_directory.to_str().unwrap(),
        ])
    }

    pub fn act(&self, mode: AuricOperationMode) -> Result<(), AuricError> {
        match mode {
            AuricOperationMode::Mount => return self.mount(),
            AuricOperationMode::Unmount => return self.unmount(),
            AuricOperationMode::Rsync => return self.rsync(),
        }
    }
}

fn main_impl() -> Result<(), AuricError> {
    let action = get_action()?;
    let auric_impl = AuricImpl::new()?;
    auric_impl.act(action)
}

fn main() {
    std::process::exit(match main_impl() {
        Ok(_) => 0,
        Err(e) => {
            eprintln!("{:?}", e);
            1
        }
    });
}
<commit_msg>apricot-auric: Add `push` command<commit_after>use regex::Regex;
use std::path::PathBuf;
use std::result::Result;
use subprocess::{Exec, ExitStatus, Redirection};

const LOOP_BACKING_DEVICE_BASENAME: &'static str = "flaglock6-home";
const LOOP_DEVICE_PARTITION_LABEL: &'static str = "fl6";
const RSYNC_DOT_NET_REMOTE_DIR: &'static str = "usw-s007.rsync.net:./";

const RUN_MEDIA_KALVIN: &'static str = "/run/media/kalvin";

#[derive(Debug)]
pub enum AuricError {
    Invocation(String),
    Io(String),
    Subprocess(String),
    NotFound,
}

enum AuricOperationMode {
    Mount,
    Unmount,
    Rsync,
    RunAll,
}

impl From<subprocess::PopenError> for AuricError {
    fn from(err: subprocess::PopenError) -> AuricError {
        AuricError::Subprocess(err.to_string())
    }
}

struct SshfsManager {
    mountpoint: PathBuf,
}

struct LoopManager {
    target: Regex,
    backing: PathBuf,
}

struct LuksManager {
    device: PathBuf,
}

struct AuricImpl {
    sshfs_manager: SshfsManager,
    loop_manager: LoopManager,
    luks_manager: LuksManager,
}

fn exec_with_stdout(command: &str, args: &[&str], error_hint: &str) -> Result<String, AuricError> {
    let result = Exec::cmd(command)
        .args(args)
        .stdout(Redirection::Pipe)
        .stderr(Redirection::Pipe)
        .capture()?;
    if !result.success() {
        return Err(AuricError::Subprocess(format!(
            "{} failed: ``{}''",
            error_hint,
            result.stderr_str(),
        )));
    }
    Ok(result.stdout_str())
}

fn exec(command: &str, args: &[&str], error_hint: &str) -> Result<(), AuricError> {
    exec_with_stdout(command, args, error_hint).map(|_stdout_str| ())
}

fn exec_rsync(args: &[&str]) -> Result<(), AuricError> {
    let result = Exec::cmd("rsync").args(args).join()?;
    if !result.success() {
        match result {
            ExitStatus::Exited(code) => {
                return Err(AuricError::Subprocess(format!(
                    "rsync exited with code {}",
                    code
                )))
            }
            ExitStatus::Signaled(signum) => {
                return Err(AuricError::Subprocess(format!(
                    "rsync exited with signal {}",
                    signum
                )))
            }
            ExitStatus::Other(code) => {
                return Err(AuricError::Subprocess(format!(
                    "unknown rsync error: {}",
                    code
                )))
            }
            ExitStatus::Undetermined => {
                return Err(AuricError::Subprocess("unknown rsync error!".to_string()))
            }
        }
    }
    Ok(())
}

impl SshfsManager {
    pub fn new() -> Result<SshfsManager, AuricError> {
        let xdg_runtime_dir = match std::env::var("XDG_RUNTIME_DIR") {
            Ok(val) => val,
            Err(e) => {
                return Err(AuricError::Invocation(format!(
                    "fatal error getting ${{XDG_RUNTIME_DIR}}: ``{}''",
                    e
                )))
            }
        };
        let mut mountpoint = PathBuf::new();
        mountpoint.push(xdg_runtime_dir);
        mountpoint.push("rsync.net-mountpoint");

        Ok(SshfsManager {
            mountpoint: mountpoint,
        })
    }

    fn ensure_mountpoint_is_dir(&self) -> Result<(), AuricError> {
        if self.mountpoint.is_dir() {
            return Ok(());
        }
        std::fs::create_dir(self.mountpoint.as_path())
            .map_err(|e| AuricError::Io(format!("bad mountpoint: ``{}''", e)))
    }

    // Does _not_ ensure that backing device exists.
    pub fn loop_backing_device_path(&self) -> PathBuf {
        let mut result: PathBuf = self.mountpoint.clone();
        result.push(LOOP_BACKING_DEVICE_BASENAME);
        result
    }

    fn loop_backing_device_present(&self) -> bool {
        self.loop_backing_device_path().is_file()
    }

    pub fn mount(&self) -> Result<(), AuricError> {
        self.ensure_mountpoint_is_dir()?;
        if self.loop_backing_device_present() {
            return Ok(());
        }

        // Invoke `sshfs`
        // *    with compression,
        // *    allowing other users to access the mounted filesystem
        //      (necessary to allow loop-mounts), and
        // *    attempting to reconnect if we lose the connection.
        exec(
            "sshfs",
            &[
                "-C",
                "-o",
                "allow_other,reconnect",
                RSYNC_DOT_NET_REMOTE_DIR,
                self.mountpoint.to_str().unwrap(),
            ],
            "sshfs mount",
        )
    }

    pub fn unmount(&self) -> Result<(), AuricError> {
        if !self.loop_backing_device_present() {
            return Ok(());
        }
        exec(
            "fusermount",
            &["-u", self.mountpoint.to_str().unwrap()],
            "fusermount -u",
        )
    }
}

impl LoopManager {
    pub fn new(backing: &PathBuf) -> LoopManager {
        let target = format!(
            r"^(/dev/loop\d)(\s+\d+){{4}}\s+({})\s+",
            backing.to_str().unwrap()
        );
        LoopManager {
            target: Regex::new(&target).unwrap(),
            backing: backing.clone(),
        }
    }

    pub fn find(&self) -> Result<PathBuf, AuricError> {
        let losetup_stdout = exec_with_stdout("losetup", &["-l"], "loop device enumeration")?;
        for line in losetup_stdout.lines() {
            if let Some(captures) = self.target.captures(line) {
                return Ok(PathBuf::from(captures.get(1).unwrap().as_str()));
            }
        }
        Err(AuricError::NotFound)
    }

    pub fn attach(&self) -> Result<(), AuricError> {
        if let Ok(_attached_loop) = self.find() {
            return Ok(());
        }

        exec(
            "udisksctl",
            &["loop-setup", "-f", self.backing.to_str().unwrap()],
            "loop device attach",
        )
    }

    // Note that the loop device will linger if the volume remains
    // unlocked. Prefer not to call this before locking.
    pub fn detach(&self) -> Result<(), AuricError> {
        let attached_loop = match self.find() {
            Ok(path) => path,
            Err(e) => {
                if let AuricError::NotFound = e {
                    return Ok(());
                }
                return Err(e);
            }
        };
        exec(
            "udisksctl",
            &["loop-delete", "-b", attached_loop.to_str().unwrap()],
            "loop device detach",
        )
    }
}

impl LuksManager {
    pub fn new() -> LuksManager {
        let mut device = PathBuf::from("/dev/disk/by-label");
        device.push(LOOP_DEVICE_PARTITION_LABEL);
        LuksManager { device: device }
    }

    pub fn unlock(&self, locked_device: &PathBuf) -> Result<(), AuricError> {
        exec(
            "udisksctl",
            &["unlock", "-b", locked_device.to_str().unwrap()],
            format!("unlocking {}", locked_device.to_str().unwrap()).as_str(),
        )
    }

    pub fn lock(&self, underlying_device: &PathBuf) -> Result<(), AuricError> {
        exec(
            "udisksctl",
            &["lock", "-b", underlying_device.to_str().unwrap()],
            format!("locking {}", underlying_device.to_str().unwrap()).as_str(),
        )
    }

    pub fn mount(&self) -> Result<(), AuricError> {
        exec(
            "udisksctl",
            &["mount", "-b", self.device.to_str().unwrap()],
            format!("mounting {}", self.device.to_str().unwrap()).as_str(),
        )
    }

    pub fn unmount(&self) -> Result<(), AuricError> {
        exec(
            "udisksctl",
            &["unmount", "-b", self.device.to_str().unwrap()],
            format!("unmounting {}", self.device.to_str().unwrap()).as_str(),
        )
    }
}

fn get_action() -> Result<AuricOperationMode, AuricError> {
    let mut args_iter = std::env::args();
    args_iter.next();
    if let Some(action) = args_iter.next() {
        match action.as_str() {
            "mount" => return Ok(AuricOperationMode::Mount),
            "unmount" => return Ok(AuricOperationMode::Unmount),
            "rsync" => return Ok(AuricOperationMode::Rsync),
            "push" => return Ok(AuricOperationMode::RunAll),
            _ => {
                return Err(AuricError::Invocation(format!(
                    "unknown action: ``{}''",
                    action
                )))
            }
        }
    }
    Err(AuricError::Invocation("no action given".to_string()))
}

impl AuricImpl {
    pub fn new() -> Result<AuricImpl, AuricError> {
        let sshfs_manager = SshfsManager::new()?;
        let loop_backing_device_path = sshfs_manager.loop_backing_device_path();
        Ok(AuricImpl {
            sshfs_manager: sshfs_manager,
            loop_manager: LoopManager::new(&loop_backing_device_path),
            luks_manager: LuksManager::new(),
        })
    }

    fn mount(&self) -> Result<(), AuricError> {
        println!("{}", "Mounting sshfs...");
        self.sshfs_manager.mount()?;
        println!("{}", "Attaching loop device...");
        self.loop_manager.attach()?;
        println!("{}", "Finding newly attached loop device...");
        let loop_device = self.loop_manager.find()?;
        println!("{}", "Unlocking volume...");
        self.luks_manager.unlock(&loop_device)?;
        println!("{}", "Mounting volume...");
        self.luks_manager.mount()
    }

    fn unmount(&self) -> Result<(), AuricError> {
        println!("{}", "Unmounting volume...");
        self.luks_manager.unmount()?;
        println!("{}", "Finding backing loop device...");
        let loop_device = self.loop_manager.find()?;
        println!("{}", "Locking volume...");
        self.luks_manager.lock(&loop_device)?;
        println!("{}", "Detaching loop device...");
        self.loop_manager.detach()?;
        println!("{}", "Unmounting sshfs...");
        self.sshfs_manager.unmount()
    }

    fn rsync(&self) -> Result<(), AuricError> {
        // I'm not pulling in the `home_dir` crate just to grab a value
        // that I suspect will be immutable for many years to come.
        // Likewise, the user mount directory is lazily hardcoded.
        let mut remote_directory = PathBuf::from(RUN_MEDIA_KALVIN);
        remote_directory.push(LOOP_DEVICE_PARTITION_LABEL);
        if !remote_directory.is_dir() {
            return Err(AuricError::Invocation(format!(
                "remote directory ``{}'' not mounted",
                remote_directory.display()
            )));
        }

        exec_rsync(&[
            "--delete",
            "-avPS",
            "--exclude=/.cache/",
            "--exclude=/.cargo/",
            "--exclude=/.local/share/",
            "--exclude=/.mozilla/",
            "--exclude=/.thunderbird/",
            "--exclude=/Downloads/.firefox-nightly/",
            "--exclude=/Downloads/.thunderbird-beta/",
            "--delete-excluded",
            "/home/kalvin/",
            remote_directory.to_str().unwrap(),
        ])
    }

    fn run_all(&self) -> Result<(), AuricError> {
        self.mount()?;
        self.rsync()?;
        self.unmount()
    }

    pub fn act(&self, mode: AuricOperationMode) -> Result<(), AuricError> {
        match mode {
            AuricOperationMode::Mount => return self.mount(),
            AuricOperationMode::Unmount => return self.unmount(),
            AuricOperationMode::Rsync => return self.rsync(),
            AuricOperationMode::RunAll => return self.run_all(),
        }
    }
}

fn main_impl() -> Result<(), AuricError> {
    let action = get_action()?;
    let auric_impl = AuricImpl::new()?;
    auric_impl.act(action)
}

fn main() {
    std::process::exit(match main_impl() {
        Ok(_) => 0,
        Err(e) => {
            eprintln!("{:?}", e);
            1
        }
    });
}
<|endoftext|>


<commit_before>use bifrost::vector_clock::{VectorClock, StandardVectorClock, ServerVectorClock};
use bifrost::utils::time::get_time;
use chashmap::CHashMap;
use std::collections::{BTreeMap, BTreeSet};
use ram::types::{Id};
use ram::cell::{Cell, ReadError, WriteError};
use server::NebServer;
use futures::sync::mpsc::{Sender, Receiver, channel};
use super::*;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(TNX_MANAGER_RPC_SERVICE) as u64;

#[derive(Debug, Serialize, Deserialize)]
pub enum TMError {
    TransactionNotFound,
    CannotLocateCellServer,
    NoResponseFromCellServer,
}

struct DataObject {
    server: u64,
    cell: Cell
}

struct Transaction {
    start_time: i64, // use for timeout detecting
    id: TransactionId,
    data: BTreeMap<Id, DataObject>,
    writes: BTreeSet<Id>,
    await_chan: (Sender<()>, Receiver<()>)
}

service! {
    rpc begin() -> TransactionId;
    rpc read(tid: TransactionId, id: Id) -> TransactionExecResult<Cell, ReadError> | TMError;
    rpc write(tid: TransactionId, id: Id, cell: Cell) -> TransactionExecResult<(), WriteError>;
    rpc update(tid: TransactionId, cell: Cell) -> TransactionExecResult<(), WriteError>;
    rpc remove(tid: TransactionId, id: Id) -> TransactionExecResult<(), WriteError>;

    rpc commit(tid: TransactionId);
    rpc abort(tid: TransactionId);

    rpc go_ahead(tid: BTreeSet<TransactionId>); // invoked by data site to continue on it's transaction in case of waiting
}

pub struct TransactionManager {
    server: Arc<NebServer>,
    transactions: CHashMap<TransactionId, Transaction>,
    data_sites: CHashMap<u64, Arc<data_site::AsyncServiceClient>>,
}
dispatch_rpc_service_functions!(TransactionManager);

impl TransactionManager {
    pub fn new(server: &Arc<NebServer>) -> Arc<TransactionManager> {
        Arc::new(TransactionManager {
            server: server.clone(),
            transactions: CHashMap::new(),
            data_sites: CHashMap::new()
        })
    }
}

impl TransactionManager {
    fn get_data_site(&self, server_id: u64) -> io::Result<(Arc<data_site::AsyncServiceClient>, u64)> {
        if !self.data_sites.contains_key(&server_id) {
            let client = self.server.get_member_by_server_id(server_id)?;
            self.data_sites.upsert(server_id, || {
                data_site::AsyncServiceClient::new(DEFAULT_SERVICE_ID, &client)
            }, |_| {});
        }
        Ok((self.data_sites .get(&server_id).unwrap().clone(), server_id))
    }
    fn get_data_site_by_id(&self, id: &Id) -> io::Result<(Arc<data_site::AsyncServiceClient>, u64)> {
        match self.server.get_server_id_by_id(id) {
            Some(id) => self.get_data_site(id),
            _ => Err(io::Error::new(io::ErrorKind::NotFound, "cannot find data site for this id"))
        }
    }
    fn get_clock(&self) -> StandardVectorClock {
        self.server.tnx_peer.clock.to_clock()
    }
    fn merge_clock(&self, clock: &StandardVectorClock) {
        self.server.tnx_peer.clock.merge_with(clock)
    }
}

impl Service for TransactionManager {
    fn begin(&self) -> Result<TransactionId, ()> {
        let id = self.server.tnx_peer.clock.inc();
        self.transactions.insert(id.clone(), Transaction {
            start_time: get_time(),
            id: id.clone(),
            data: BTreeMap::new(),
            writes: BTreeSet::new(),
            await_chan: channel(1)
        });
        Ok(id)
    }
    fn read(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<Cell, ReadError>, TMError> {
        let mut tnx = {
            match self.transactions.get_mut(tid) {
                Some(tnx) => tnx,
                _ => {return Err(TMError::TransactionNotFound)}
            }
        };
        if let Some(dataObj) = tnx.data.get(id) {
            return Ok(TransactionExecResult::Accepted(dataObj.cell.clone())) // read from cache
        }
        let server = self.get_data_site_by_id(&id);
        match server {
            Ok((server, server_id)) => {
                let self_server_id = self.server.server_id;
                let read_response = server.read(
                    &self_server_id,
                    &self.get_clock(),
                    tid, id
                ).wait();
                match read_response {
                    Ok(dsr) => {
                        let dsr = dsr.unwrap();
                        self.merge_clock(&dsr.clock);
                        match dsr.payload {
                            TransactionExecResult::Accepted(ref cell) => {
                                tnx.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: cell.clone()
                                });
                            },
                            _ => {}
                        }
                        Ok(dsr.payload)
                    },
                    Err(e) => {
                        error!("{:?}", e);
                        Err(TMError::NoResponseFromCellServer)
                    }
                }
            },
            Err(e) => {
                error!("{:?}", e);
                Err(TMError::CannotLocateCellServer)
            }
        }
    }
    fn write(&self, tid: &TransactionId, id: &Id, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, ()> {
        Err(())
    }
    fn update(&self, tid: &TransactionId, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, ()> {
        Err(())
    }
    fn remove(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<(), WriteError>, ()> {
        Err(())
    }
    fn commit(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn abort(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn go_ahead(&self, tid: &BTreeSet<TransactionId>) -> Result<(), ()> {
        Err(())
    }
}
<commit_msg>deal with unexisted reads and removes for the future<commit_after>use bifrost::vector_clock::{VectorClock, StandardVectorClock, ServerVectorClock};
use bifrost::utils::time::get_time;
use chashmap::CHashMap;
use std::collections::{BTreeMap, BTreeSet};
use ram::types::{Id};
use ram::cell::{Cell, ReadError, WriteError};
use server::NebServer;
use futures::sync::mpsc::{Sender, Receiver, channel};
use super::*;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(TNX_MANAGER_RPC_SERVICE) as u64;

#[derive(Debug, Serialize, Deserialize)]
pub enum TMError {
    TransactionNotFound,
    CannotLocateCellServer,
    NoResponseFromCellServer,
}

struct DataObject {
    server: u64,
    cell: Option<Cell>
}

struct Transaction {
    start_time: i64, // use for timeout detecting
    id: TransactionId,
    data: BTreeMap<Id, DataObject>,
    writes: BTreeSet<Id>,
    await_chan: (Sender<()>, Receiver<()>)
}

service! {
    rpc begin() -> TransactionId;
    rpc read(tid: TransactionId, id: Id) -> TransactionExecResult<Cell, ReadError> | TMError;
    rpc write(tid: TransactionId, id: Id, cell: Cell) -> TransactionExecResult<(), WriteError>;
    rpc update(tid: TransactionId, cell: Cell) -> TransactionExecResult<(), WriteError>;
    rpc remove(tid: TransactionId, id: Id) -> TransactionExecResult<(), WriteError>;

    rpc commit(tid: TransactionId);
    rpc abort(tid: TransactionId);

    rpc go_ahead(tid: BTreeSet<TransactionId>); // invoked by data site to continue on it's transaction in case of waiting
}

pub struct TransactionManager {
    server: Arc<NebServer>,
    transactions: CHashMap<TransactionId, Transaction>,
    data_sites: CHashMap<u64, Arc<data_site::AsyncServiceClient>>,
}
dispatch_rpc_service_functions!(TransactionManager);

impl TransactionManager {
    pub fn new(server: &Arc<NebServer>) -> Arc<TransactionManager> {
        Arc::new(TransactionManager {
            server: server.clone(),
            transactions: CHashMap::new(),
            data_sites: CHashMap::new()
        })
    }
}

impl TransactionManager {
    fn get_data_site(&self, server_id: u64) -> io::Result<(Arc<data_site::AsyncServiceClient>, u64)> {
        if !self.data_sites.contains_key(&server_id) {
            let client = self.server.get_member_by_server_id(server_id)?;
            self.data_sites.upsert(server_id, || {
                data_site::AsyncServiceClient::new(DEFAULT_SERVICE_ID, &client)
            }, |_| {});
        }
        Ok((self.data_sites .get(&server_id).unwrap().clone(), server_id))
    }
    fn get_data_site_by_id(&self, id: &Id) -> io::Result<(Arc<data_site::AsyncServiceClient>, u64)> {
        match self.server.get_server_id_by_id(id) {
            Some(id) => self.get_data_site(id),
            _ => Err(io::Error::new(io::ErrorKind::NotFound, "cannot find data site for this id"))
        }
    }
    fn get_clock(&self) -> StandardVectorClock {
        self.server.tnx_peer.clock.to_clock()
    }
    fn merge_clock(&self, clock: &StandardVectorClock) {
        self.server.tnx_peer.clock.merge_with(clock)
    }
}

impl Service for TransactionManager {
    fn begin(&self) -> Result<TransactionId, ()> {
        let id = self.server.tnx_peer.clock.inc();
        self.transactions.insert(id.clone(), Transaction {
            start_time: get_time(),
            id: id.clone(),
            data: BTreeMap::new(),
            writes: BTreeSet::new(),
            await_chan: channel(1)
        });
        Ok(id)
    }
    fn read(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<Cell, ReadError>, TMError> {
        let mut tnx = {
            match self.transactions.get_mut(tid) {
                Some(tnx) => tnx,
                _ => {return Err(TMError::TransactionNotFound)}
            }
        };
        if let Some(dataObj) = tnx.data.get(id) {
            match dataObj.cell {
                Some(ref cell) => {
                    return Ok(TransactionExecResult::Accepted(cell.clone())) // read from cache
                },
                None => {
                   return Ok(TransactionExecResult::Error(ReadError::CellDoesNotExisted))
                }
            }
        }
        let server = self.get_data_site_by_id(&id);
        match server {
            Ok((server, server_id)) => {
                let self_server_id = self.server.server_id;
                let read_response = server.read(
                    &self_server_id,
                    &self.get_clock(),
                    tid, id
                ).wait();
                match read_response {
                    Ok(dsr) => {
                        let dsr = dsr.unwrap();
                        self.merge_clock(&dsr.clock);
                        match dsr.payload {
                            TransactionExecResult::Accepted(ref cell) => {
                                tnx.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: Some(cell.clone())
                                });
                            },
                            TransactionExecResult::Error(ReadError::CellDoesNotExisted) => {
                                tnx.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: None
                                });
                            }
                            _ => {}
                        }
                        Ok(dsr.payload)
                    },
                    Err(e) => {
                        error!("{:?}", e);
                        Err(TMError::NoResponseFromCellServer)
                    }
                }
            },
            Err(e) => {
                error!("{:?}", e);
                Err(TMError::CannotLocateCellServer)
            }
        }
    }
    fn write(&self, tid: &TransactionId, id: &Id, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, ()> {
        Err(())
    }
    fn update(&self, tid: &TransactionId, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, ()> {
        Err(())
    }
    fn remove(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<(), WriteError>, ()> {
        Err(())
    }
    fn commit(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn abort(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn go_ahead(&self, tid: &BTreeSet<TransactionId>) -> Result<(), ()> {
        Err(())
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Read;

use common::manhattan_distance;
use common::Solution;

type Coordinate = (usize, usize);

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
struct Unit {
    pos: Coordinate,
    hp: u8,
    power: u8,
    faction: char,
}

impl Default for Unit {
    fn default() -> Self {
        Unit {
            pos: (0, 0),
            hp: 200,
            power: 3,
            faction: 'E',
        }
    }
}

impl Unit {
    pub fn is_alive(&self) -> bool {
        self.hp > 0
    }
}

#[derive(Default)]
pub struct Day15 {
    walls: Vec<Vec<bool>>,
    units: Vec<Unit>,
    alive: [usize; 2],
}

impl Day15 {
    pub fn new() -> Self {
        Default::default()
    }

    fn read_input(&mut self, input: &mut Read) {
        let reader = BufReader::new(input);

        for (y, line) in reader.lines().enumerate() {
            let line = line.unwrap();
            let mut current = vec![false; line.len()];

            for (x, c) in line.chars().enumerate() {
                match c {
                    '#' => { current[x] = true; }
                    'G' => {
                        self.units.push(Unit {
                            pos: (y, x),
                            faction: 'G',
                            ..Default::default()
                        });
                        self.alive[1] += 1;
                    }
                    'E' => {
                        self.units.push(Unit {
                            pos: (y, x),
                            ..Default::default()
                        });
                        self.alive[0] += 1;
                    }
                    '.' => {}
                    c => panic!("Invalid tile {}!", c),
                }
            }
            self.walls.push(current);
        }
    }

    fn get_movement(&self, unit: usize) -> Option<Coordinate> {
        let initial = self.units[unit].pos;
        let faction = self.units[unit].faction;

        let positions: HashSet<Coordinate> = self.units.iter()
            .filter(|x| x.faction != faction && x.is_alive())
            .map(|x| x.pos).collect();

        let all_positions: HashSet<Coordinate> = self.units.iter()
            .filter(|x| x.is_alive())
            .map(|x| x.pos).collect();

        let mut todo = VecDeque::new();
        let mut prev = HashMap::new();

        todo.push_back(initial);

        while let Some((y, x)) = todo.pop_front() {
            let next = [
                (y - 1, x),
                (y, x - 1),
                (y, x + 1),
                (y + 1, x),
            ];

            for pos in &next {
                if !prev.contains_key(pos) && !self.walls[pos.0][pos.1] {
                    prev.insert(*pos, (y, x));
                    if positions.contains(pos) {
                        if (y, x) == initial {
                            return None;
                        }

                        let mut next_pos = *pos;
                        // Found the nearest enemy
                        while let Some(prev_pos) = prev.get(&next_pos) {
                            if *prev_pos != initial {
                                next_pos = *prev_pos;
                            } else {
                                break;
                            }
                        }

                        return Some(next_pos);
                    } else if !all_positions.contains(pos) {
                        todo.push_back(*pos);
                    }
                }
            }
        }
        None
    }

    fn get_attack(&self, unit: usize) -> Option<usize> {
        let initial = self.units[unit].pos;
        let faction = self.units[unit].faction;

        let to_attack = self.units.iter()
            .enumerate()
            .filter(|(_, x)| x.faction != faction && x.is_alive())
            .filter(|(_, x)| manhattan_distance(x.pos, initial) == 1)
            .min_by(|&(_, a), &(_, b)| a.hp.cmp(&b.hp).then(a.pos.cmp(&b.pos)));

        if let Some((index, _)) = to_attack {
            Some(index)
        } else {
            None
        }
    }

    fn simulate(&mut self) -> bool {
        self.units.sort_unstable();
        for i in 0..self.units.len() {
            if !self.units[i].is_alive() {
                continue;
            }

            if self.alive[0] == 0 || self.alive[1] == 0 {
                return false;
            }

            if let Some(new_pos) = self.get_movement(i) {
                self.units[i].pos = new_pos;
            }

            if let Some(target) = self.get_attack(i) {
                let power = self.units[i].power;
                let target = &mut self.units[target];
                target.hp = target.hp.saturating_sub(power);

                if target.hp == 0 {
                    match target.faction {
                        'E' => { self.alive[0] -= 1 }
                        'G' => { self.alive[1] -= 1 },
                        _ => panic!(),
                    };
                }
            }
        }

        true
    }

    #[allow(dead_code)]
    fn print(&self) {
        let positions: HashMap<_, _> = self.units.iter()
            .filter(|x| x.is_alive())
            .map(|x| (x.pos, x))
            .collect();

        for y in 0..self.walls.len() {
            let mut buf = String::new();
            let mut unit_buf = String::new();

            for x in 0..self.walls[y].len() {
                if let Some(unit) = positions.get(&(y, x)) {
                    buf.push(unit.faction);

                    unit_buf += &format!("    {}({})", unit.faction, unit.hp);
                } else if self.walls[y][x] {
                    buf.push('#');
                } else {
                    buf.push('.');
                }
            }
            println!("{}{}", buf, unit_buf);
        }
    }
}

impl Solution for Day15 {
    fn part1(&mut self, input: &mut Read) -> String {
        self.read_input(input);
        let mut rounds = 0;
        while self.simulate() {
            rounds += 1;
            //println!("Result after round {}: ", rounds);
            //self.print();
        }
        let result: usize = rounds * self.units.iter().map(|x| x.hp as usize)
            .sum::<usize>();

        format!("{}", result)
    }

    fn part2(&mut self, _input: &mut Read) -> String {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use common::Solution;
    use day15::Day15;

    const SAMPLE_INPUT: [&[u8]; 6] = [
        include_bytes!("samples/15.1.txt"),
        include_bytes!("samples/15.2.txt"),
        include_bytes!("samples/15.3.txt"),
        include_bytes!("samples/15.4.txt"),
        include_bytes!("samples/15.5.txt"),
        include_bytes!("samples/15.6.txt"),
    ];

    const SAMPLE_OUTPUT: [&str; 6] = [
        "27730",
        "36334",
        "39514",
        "27755",
        "28944",
        "18740",
    ];

    #[test]
    fn sample_part1() {
        for (input, output) in SAMPLE_INPUT.iter().zip(SAMPLE_OUTPUT.iter()) {
            let mut instance = Day15::new();
            assert_eq!(*output, instance.part1(&mut input.as_ref()));
        }
    }
}
<commit_msg>Clean up and simplify.<commit_after>use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Read;

use common::manhattan_distance;
use common::Solution;

type Coordinate = (usize, usize);

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
struct Unit {
    pos: Coordinate,
    hp: u8,
    power: u8,
    faction: char,
}

impl Default for Unit {
    fn default() -> Self {
        Unit {
            pos: (0, 0),
            hp: 200,
            power: 3,
            faction: 'E',
        }
    }
}

impl Unit {
    pub fn is_alive(&self) -> bool {
        self.hp > 0
    }
}

#[derive(Default)]
pub struct Day15 {
    walls: Vec<Vec<bool>>,
    units: Vec<Unit>,
    alive: [usize; 2],
}

impl Day15 {
    pub fn new() -> Self {
        Default::default()
    }

    fn read_input(&mut self, input: &mut Read) {
        let reader = BufReader::new(input);

        for (y, line) in reader.lines().enumerate() {
            let line = line.unwrap();
            let mut current = vec![false; line.len()];

            for (x, c) in line.chars().enumerate() {
                match c {
                    '#' => { current[x] = true; }
                    'E' | 'G' => {
                        self.units.push(Unit {
                            pos: (y, x),
                            faction: c,
                            ..Default::default()
                        });
                        self.alive[if c == 'E' { 0 } else { 1 }] += 1;
                    }
                    '.' => {}
                    c => panic!("Invalid tile {}!", c),
                }
            }
            self.walls.push(current);
        }
    }

    fn get_movement(&self, unit: usize) -> Option<Coordinate> {
        let initial = self.units[unit].pos;
        let faction = self.units[unit].faction;

        let enemy_positions: HashSet<Coordinate> = self.units.iter()
            .filter(|x| x.faction != faction && x.is_alive())
            .map(|x| x.pos).collect();

        let all_positions: HashSet<Coordinate> = self.units.iter()
            .filter(|x| x.is_alive())
            .map(|x| x.pos).collect();

        let mut todo = VecDeque::new();
        let mut prev: HashMap<Coordinate, Coordinate> = HashMap::new();

        todo.push_back(initial);

        while let Some((y, x)) = todo.pop_front() {
            let next = [
                (y - 1, x),
                (y, x - 1),
                (y, x + 1),
                (y + 1, x),
            ];

            for pos in &next {
                if !prev.contains_key(pos) && !self.walls[pos.0][pos.1] {
                    if enemy_positions.contains(pos) {
                        return prev.remove(&(y, x));
                    } else if !all_positions.contains(pos) {;
                        let prev_step = *prev.get(&(y, x)).unwrap_or(pos);
                        prev.insert(*pos, prev_step);
                        todo.push_back(*pos);
                    }
                }
            }
        }
        None
    }

    fn get_attack(&self, unit: usize) -> Option<usize> {
        let initial = self.units[unit].pos;
        let faction = self.units[unit].faction;

        let to_attack = self.units.iter()
            .enumerate()
            .filter(|(_, x)| x.faction != faction && x.is_alive())
            .filter(|(_, x)| manhattan_distance(x.pos, initial) == 1)
            .min_by(|&(_, a), &(_, b)| a.hp.cmp(&b.hp).then(a.pos.cmp(&b.pos)));

        if let Some((index, _)) = to_attack {
            Some(index)
        } else {
            None
        }
    }

    fn simulate(&mut self) -> bool {
        self.units.sort_unstable();
        for i in 0..self.units.len() {
            if !self.units[i].is_alive() {
                continue;
            }

            if self.alive[0] == 0 || self.alive[1] == 0 {
                return false;
            }

            if let Some(new_pos) = self.get_movement(i) {
                self.units[i].pos = new_pos;
            }

            if let Some(target) = self.get_attack(i) {
                let power = self.units[i].power;
                let target = &mut self.units[target];
                target.hp = target.hp.saturating_sub(power);

                if target.hp == 0 {
                    match target.faction {
                        'E' => { self.alive[0] -= 1 }
                        'G' => { self.alive[1] -= 1 }
                        _ => panic!(),
                    };
                }
            }
        }

        true
    }

    #[allow(dead_code)]
    fn print(&self) {
        let positions: HashMap<_, _> = self.units.iter()
            .filter(|x| x.is_alive())
            .map(|x| (x.pos, x))
            .collect();

        for y in 0..self.walls.len() {
            let mut buf = String::new();
            let mut unit_buf = String::new();

            for x in 0..self.walls[y].len() {
                if let Some(unit) = positions.get(&(y, x)) {
                    buf.push(unit.faction);

                    unit_buf += &format!("    {}({})", unit.faction, unit.hp);
                } else if self.walls[y][x] {
                    buf.push('#');
                } else {
                    buf.push('.');
                }
            }
            println!("{}{}", buf, unit_buf);
        }
    }
}

impl Solution for Day15 {
    fn part1(&mut self, input: &mut Read) -> String {
        self.read_input(input);
        let mut rounds = 0;
        while self.simulate() {
            rounds += 1;
        }
        let result: usize = rounds * self.units.iter().map(|x| x.hp as usize)
            .sum::<usize>();

        format!("{}", result)
    }

    fn part2(&mut self, _input: &mut Read) -> String {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use common::Solution;
    use day15::Day15;

    const SAMPLE_INPUT: [&[u8]; 6] = [
        include_bytes!("samples/15.1.txt"),
        include_bytes!("samples/15.2.txt"),
        include_bytes!("samples/15.3.txt"),
        include_bytes!("samples/15.4.txt"),
        include_bytes!("samples/15.5.txt"),
        include_bytes!("samples/15.6.txt"),
    ];

    const SAMPLE_OUTPUT: [&str; 6] = [
        "27730",
        "36334",
        "39514",
        "27755",
        "28944",
        "18740",
    ];

    #[test]
    fn sample_part1() {
        for (input, output) in SAMPLE_INPUT.iter().zip(SAMPLE_OUTPUT.iter()) {
            let mut instance = Day15::new();
            assert_eq!(*output, instance.part1(&mut input.as_ref()));
        }
    }
}
<|endoftext|>


<commit_before>use anyhow::Result;

pub fn parse(input: &str) -> Result<&[u8]> {
    Ok(input.as_bytes())
}

enum ParseResult {
    Ok,
    Incomplete,
    Unexpected(u8),
}

fn parse_line(line: &[u8]) -> ParseResult {
    let mut stack = Vec::with_capacity(line.len());
    for ch in line.iter().copied() {
        match ch {
            b'(' | b'[' | b'{' | b'<' => stack.push(ch),
            b')' => {
                if let Some(b'(') = stack.last() {
                    stack.pop();
                } else {
                    return ParseResult::Unexpected(b')');
                }
            }
            b']' => {
                if let Some(b'[') = stack.last() {
                    stack.pop();
                } else {
                    return ParseResult::Unexpected(b']');
                }
            }
            b'}' => {
                if let Some(b'{') = stack.last() {
                    stack.pop();
                } else {
                    return ParseResult::Unexpected(b'}');
                }
            }
            b'>' => {
                if let Some(b'<') = stack.last() {
                    stack.pop();
                } else {
                    return ParseResult::Unexpected(b'>');
                }
            }
            _ => continue,
        }
    }
    if stack.is_empty() {
        ParseResult::Ok
    } else {
        ParseResult::Incomplete
    }
}

pub fn part1(input: &[u8]) -> usize {
    input
        .split(|c| *c == b'\n')
        .filter_map(|l| match parse_line(l) {
            ParseResult::Unexpected(c) => match c {
                b')' => Some(3),
                b']' => Some(57),
                b'}' => Some(1197),
                b'>' => Some(25137),
                other => panic!("invalid unexpected char: {}", other),
            },
            _ => None,
        })
        .sum()
}

pub fn part2(_input: &[u8]) -> &'static str {
    "not implemented"
}

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

    const INPUT: &str = r"
    [({(<(())[]>[[{[]{<()<>>
    [(()[<>])]({[<{<<[]>>(
    {([(<{}[<>[]}>{[]{[(<()>
    (((({<>}<{<{<>}{[]{[]{}
    [[<[([]))<([[{}[[()]]]
    [{[{({}]{}}([{[{{{}}([]
    {<[[]]>}<{[{[{[]{()[[[]
    [<(<(<(<{}))><([]([]()
    <{([([[(<>()){}]>(<<{{
    <{([{{}}[<[[[<>{}]]]>[]]";

    #[test]
    fn test_part1() {
        assert_eq!(part1(INPUT.as_bytes()), 26397);
    }
}
<commit_msg>2021 day 10 part 2<commit_after>use anyhow::Result;

pub fn parse(input: &str) -> Result<&[u8]> {
    Ok(input.as_bytes())
}

enum ParseResult {
    Ok,
    Incomplete(Vec<u8>),
    Unexpected(u8),
}

fn parse_line(line: &[u8]) -> ParseResult {
    let mut stack = Vec::with_capacity(line.len());
    for ch in line.iter().copied() {
        match ch {
            b'(' | b'[' | b'{' | b'<' => stack.push(ch),
            b')' => {
                if let Some(b'(') = stack.last() {
                    stack.pop();
                } else {
                    return ParseResult::Unexpected(b')');
                }
            }
            b']' => {
                if let Some(b'[') = stack.last() {
                    stack.pop();
                } else {
                    return ParseResult::Unexpected(b']');
                }
            }
            b'}' => {
                if let Some(b'{') = stack.last() {
                    stack.pop();
                } else {
                    return ParseResult::Unexpected(b'}');
                }
            }
            b'>' => {
                if let Some(b'<') = stack.last() {
                    stack.pop();
                } else {
                    return ParseResult::Unexpected(b'>');
                }
            }
            _ => continue,
        }
    }
    if stack.is_empty() {
        ParseResult::Ok
    } else {
        let needed = stack
            .into_iter()
            .rev()
            .map(|c| match c {
                b'(' => b')',
                b'[' => b']',
                b'{' => b'}',
                b'<' => b'>',
                other => panic!("invalid stack char: {}", other),
            })
            .collect();
        ParseResult::Incomplete(needed)
    }
}

pub fn part1(input: &[u8]) -> usize {
    input
        .split(|c| *c == b'\n')
        .filter_map(|l| match parse_line(l) {
            ParseResult::Unexpected(c) => match c {
                b')' => Some(3),
                b']' => Some(57),
                b'}' => Some(1197),
                b'>' => Some(25137),
                other => panic!("invalid unexpected char: {}", other),
            },
            _ => None,
        })
        .sum()
}

fn score_incomplete(needed: &[u8]) -> usize {
    needed.iter().copied().fold(0, |acc, c| {
        let add = match c {
            b')' => 1,
            b']' => 2,
            b'}' => 3,
            b'>' => 4,
            other => panic!("invalid needed char: {}", other),
        };
        5 * acc + add
    })
}

pub fn part2(input: &[u8]) -> usize {
    let mut scores: Vec<usize> = input
        .split(|c| *c == b'\n')
        .filter_map(|l| match parse_line(l) {
            ParseResult::Incomplete(needed) => Some(score_incomplete(&needed)),
            _ => None,
        })
        .collect();
    scores.sort_unstable();
    scores[scores.len() / 2]
}

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

    const INPUT: &str = r"
    [({(<(())[]>[[{[]{<()<>>
    [(()[<>])]({[<{<<[]>>(
    {([(<{}[<>[]}>{[]{[(<()>
    (((({<>}<{<{<>}{[]{[]{}
    [[<[([]))<([[{}[[()]]]
    [{[{({}]{}}([{[{{{}}([]
    {<[[]]>}<{[{[{[]{()[[[]
    [<(<(<(<{}))><([]([]()
    <{([([[(<>()){}]>(<<{{
    <{([{{}}[<[[[<>{}]]]>[]]";

    #[test]
    fn test_part1() {
        assert_eq!(part1(INPUT.as_bytes()), 26397);
    }

    #[test]
    fn test_part2() {
        assert_eq!(part2(INPUT.as_bytes()), 288957);
    }
}
<|endoftext|>


<commit_before>enum Opaque {
    Foo(i32),
    Bar
}

#[repr(u32)]
enum A {
    a1 = 0,
    a2 = 2,
    a3,
    a4 = 5,
}

#[repr(u16)]
enum B {
    b1 = 0,
    b2 = 2,
    b3,
    b4 = 5,
}

#[repr(u8)]
enum C {
    c1 = 0,
    c2 = 2,
    c3,
    c4 = 5,
}

#[no_mangle]
extern "C" fn root(x: *mut Opaque,
                   y: A,
                   z: B,
                   w: C)
{ }
<commit_msg>The test for repr(isize)/repr(usize) enum.<commit_after>enum Opaque {
    Foo(i32),
    Bar
}

#[repr(u32)]
enum A {
    a1 = 0,
    a2 = 2,
    a3,
    a4 = 5,
}

#[repr(u16)]
enum B {
    b1 = 0,
    b2 = 2,
    b3,
    b4 = 5,
}

#[repr(u8)]
enum C {
    c1 = 0,
    c2 = 2,
    c3,
    c4 = 5,
}

#[repr(usize)]
enum D {
    d1 = 0,
    d2 = 2,
    d3,
    d4 = 5,
}

#[repr(isize)]
enum E {
    e1 = 0,
    e2 = 2,
    e3,
    e4 = 5,
}

#[no_mangle]
extern "C" fn root(o: *mut Opaque,
                   a: A,
                   b: B,
                   c: C,
                   d: D,
                   e: E)
{ }
<|endoftext|>


<commit_before>#![feature(core_intrinsics)]

use std::panic::Location;

#[track_caller]
fn tracked() -> &'static Location<'static> {
    Location::caller() // most importantly, we never get line 7
}

fn nested_intrinsic() -> &'static Location<'static> {
    Location::caller()
}

fn nested_tracked() -> &'static Location<'static> {
    tracked()
}

macro_rules! caller_location_from_macro {
    () => (core::panic::Location::caller());
}

fn test_fn_ptr() {
    fn pass_to_ptr_call<T>(f: fn(T), x: T) {
        f(x);
    }

    #[track_caller]
    fn tracked_unit(_: ()) {
        let expected_line = line!() - 1;
        let location = std::panic::Location::caller();
        assert_eq!(location.file(), file!());
        assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
    }

    pass_to_ptr_call(tracked_unit, ());
}

fn main() {
    let location = Location::caller();
    let expected_line = line!() - 1;
    assert_eq!(location.file(), file!());
    assert_eq!(location.line(), expected_line);
    assert_eq!(location.column(), 20);

    let tracked = tracked();
    let expected_line = line!() - 1;
    assert_eq!(tracked.file(), file!());
    assert_eq!(tracked.line(), expected_line);
    assert_eq!(tracked.column(), 19);

    let nested = nested_intrinsic();
    assert_eq!(nested.file(), file!());
    assert_eq!(nested.line(), 11);
    assert_eq!(nested.column(), 5);

    let contained = nested_tracked();
    assert_eq!(contained.file(), file!());
    assert_eq!(contained.line(), 15);
    assert_eq!(contained.column(), 5);

    // `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
    // i.e. point to where the macro was invoked, instead of the macro itself.
    let inmacro = caller_location_from_macro!();
    let expected_line = line!() - 1;
    assert_eq!(inmacro.file(), file!());
    assert_eq!(inmacro.line(), expected_line);
    assert_eq!(inmacro.column(), 19);

    let intrinsic = core::intrinsics::caller_location();
    let expected_line = line!() - 1;
    assert_eq!(intrinsic.file(), file!());
    assert_eq!(intrinsic.line(), expected_line);
    assert_eq!(intrinsic.column(), 21);

    test_fn_ptr();
}
<commit_msg>test track_caller on trait objects<commit_after>#![feature(core_intrinsics)]

use std::panic::Location;

#[track_caller]
fn tracked() -> &'static Location<'static> {
    Location::caller() // most importantly, we never get line 7
}

fn nested_intrinsic() -> &'static Location<'static> {
    Location::caller()
}

fn nested_tracked() -> &'static Location<'static> {
    tracked()
}

macro_rules! caller_location_from_macro {
    () => (core::panic::Location::caller());
}

fn test_fn_ptr() {
    fn pass_to_ptr_call<T>(f: fn(T), x: T) {
        f(x);
    }

    #[track_caller]
    fn tracked_unit(_: ()) {
        let expected_line = line!() - 1;
        let location = std::panic::Location::caller();
        assert_eq!(location.file(), file!());
        assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
    }

    pass_to_ptr_call(tracked_unit, ());
}

fn test_trait_obj() {
    trait Tracked {
        #[track_caller]
        fn handle(&self) { // `fn` here is what the `location` should point at.
            let location = std::panic::Location::caller();
            assert_eq!(location.file(), file!());
            // we only call this via trait object, so the def site should *always* be returned
            assert_eq!(location.line(), line!() - 4);
            assert_eq!(location.column(), 9);
        }
    }

    impl Tracked for () {}
    impl Tracked for u8 {}

    let tracked: &dyn Tracked = &5u8;
    tracked.handle();

    const TRACKED: &dyn Tracked = &();
    TRACKED.handle();
}

fn main() {
    let location = Location::caller();
    let expected_line = line!() - 1;
    assert_eq!(location.file(), file!());
    assert_eq!(location.line(), expected_line);
    assert_eq!(location.column(), 20);

    let tracked = tracked();
    let expected_line = line!() - 1;
    assert_eq!(tracked.file(), file!());
    assert_eq!(tracked.line(), expected_line);
    assert_eq!(tracked.column(), 19);

    let nested = nested_intrinsic();
    assert_eq!(nested.file(), file!());
    assert_eq!(nested.line(), 11);
    assert_eq!(nested.column(), 5);

    let contained = nested_tracked();
    assert_eq!(contained.file(), file!());
    assert_eq!(contained.line(), 15);
    assert_eq!(contained.column(), 5);

    // `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
    // i.e. point to where the macro was invoked, instead of the macro itself.
    let inmacro = caller_location_from_macro!();
    let expected_line = line!() - 1;
    assert_eq!(inmacro.file(), file!());
    assert_eq!(inmacro.line(), expected_line);
    assert_eq!(inmacro.column(), 19);

    let intrinsic = core::intrinsics::caller_location();
    let expected_line = line!() - 1;
    assert_eq!(intrinsic.file(), file!());
    assert_eq!(intrinsic.line(), expected_line);
    assert_eq!(intrinsic.column(), 21);

    test_fn_ptr();
    test_trait_obj();
}
<|endoftext|>


<commit_before>use std::io;
use std::process::Command;
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};

use Arch::*;

#[allow(non_camel_case_types)]
#[derive(Copy, Clone)]
pub enum Arch {
    Armv7,
    Armv7s,
    Arm64,
    I386,
    X86_64
}

impl Arch {
    pub fn to_string(self) -> &'static str {
        match self {
            Armv7 => "armv7",
            Armv7s => "armv7s",
            Arm64 => "arm64",
            I386 => "i386",
            X86_64 => "x86_64"
        }
    }
}

pub fn get_sdk_root(sdk_name: &str) -> Result<String, String> {
    let res = Command::new("xcrun")
                      .arg("--show-sdk-path")
                      .arg("-sdk")
                      .arg(sdk_name)
                      .output()
                      .and_then(|output| {
                          if output.status.success() {
                              Ok(String::from_utf8(output.stdout).unwrap())
                          } else {
                              let error = String::from_utf8(output.stderr);
                              let error = format!("process exit with error: {}",
                                                  error.unwrap());
                              Err(io::Error::new(io::ErrorKind::Other,
                                                 &error[..]))
                          }
                      });

    match res {
        Ok(output) => Ok(output.trim().to_string()),
        Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e))
    }
}

fn build_pre_link_args(arch: Arch) -> Result<LinkArgs, String> {
    let sdk_name = match arch {
        Armv7 | Armv7s | Arm64 => "iphoneos",
        I386 | X86_64 => "iphonesimulator"
    };

    let arch_name = arch.to_string();

    let sdk_root = get_sdk_root(sdk_name)?;

    let mut args = LinkArgs::new();
    args.insert(LinkerFlavor::Gcc,
                vec!["-arch".to_string(),
                     arch_name.to_string(),
                     "-isysroot".to_string(),
                     sdk_root.clone(),
                     "-Wl,-syslibroot".to_string(),
                     sdk_root]);

    Ok(args)
}

fn target_cpu(arch: Arch) -> String {
    match arch {
        Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher
        Armv7s => "cortex-a9",
        Arm64 => "cyclone",
        I386 => "yonah",
        X86_64 => "core2",
    }.to_string()
}

pub fn opts(arch: Arch) -> Result<TargetOptions, String> {
    let pre_link_args = build_pre_link_args(arch)?;
    Ok(TargetOptions {
        cpu: target_cpu(arch),
        dynamic_linking: false,
        executables: true,
        pre_link_args,
        has_elf_tls: false,
        eliminate_frame_pointer: false,
        .. super::apple_base::opts()
    })
}
<commit_msg>Rollup merge of #62903 - swolchok:ios-sdkroot, r=alexcrichton<commit_after>use std::env;
use std::io;
use std::path::Path;
use std::process::Command;
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};

use Arch::*;

#[allow(non_camel_case_types)]
#[derive(Copy, Clone)]
pub enum Arch {
    Armv7,
    Armv7s,
    Arm64,
    I386,
    X86_64
}

impl Arch {
    pub fn to_string(self) -> &'static str {
        match self {
            Armv7 => "armv7",
            Armv7s => "armv7s",
            Arm64 => "arm64",
            I386 => "i386",
            X86_64 => "x86_64"
        }
    }
}

pub fn get_sdk_root(sdk_name: &str) -> Result<String, String> {
    // Following what clang does
    // (https://github.com/llvm/llvm-project/blob/
    // 296a80102a9b72c3eda80558fb78a3ed8849b341/clang/lib/Driver/ToolChains/Darwin.cpp#L1661-L1678)
    // to allow the SDK path to be set. (For clang, xcrun sets
    // SDKROOT; for rustc, the user or build system can set it, or we
    // can fall back to checking for xcrun on PATH.)
    if let Some(sdkroot) = env::var("SDKROOT").ok() {
        let sdkroot_path = Path::new(&sdkroot);
        if sdkroot_path.is_absolute() && sdkroot_path != Path::new("/") && sdkroot_path.exists() {
            return Ok(sdkroot);
        }
    }
    let res = Command::new("xcrun")
                      .arg("--show-sdk-path")
                      .arg("-sdk")
                      .arg(sdk_name)
                      .output()
                      .and_then(|output| {
                          if output.status.success() {
                              Ok(String::from_utf8(output.stdout).unwrap())
                          } else {
                              let error = String::from_utf8(output.stderr);
                              let error = format!("process exit with error: {}",
                                                  error.unwrap());
                              Err(io::Error::new(io::ErrorKind::Other,
                                                 &error[..]))
                          }
                      });

    match res {
        Ok(output) => Ok(output.trim().to_string()),
        Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e))
    }
}

fn build_pre_link_args(arch: Arch) -> Result<LinkArgs, String> {
    let sdk_name = match arch {
        Armv7 | Armv7s | Arm64 => "iphoneos",
        I386 | X86_64 => "iphonesimulator"
    };

    let arch_name = arch.to_string();

    let sdk_root = get_sdk_root(sdk_name)?;

    let mut args = LinkArgs::new();
    args.insert(LinkerFlavor::Gcc,
                vec!["-arch".to_string(),
                     arch_name.to_string(),
                     "-isysroot".to_string(),
                     sdk_root.clone(),
                     "-Wl,-syslibroot".to_string(),
                     sdk_root]);

    Ok(args)
}

fn target_cpu(arch: Arch) -> String {
    match arch {
        Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher
        Armv7s => "cortex-a9",
        Arm64 => "cyclone",
        I386 => "yonah",
        X86_64 => "core2",
    }.to_string()
}

pub fn opts(arch: Arch) -> Result<TargetOptions, String> {
    let pre_link_args = build_pre_link_args(arch)?;
    Ok(TargetOptions {
        cpu: target_cpu(arch),
        dynamic_linking: false,
        executables: true,
        pre_link_args,
        has_elf_tls: false,
        eliminate_frame_pointer: false,
        .. super::apple_base::opts()
    })
}
<|endoftext|>


<commit_before>mod advent_of_code;

use advent_of_code::get_numbers;

use std::io;
use std::io::BufRead;

fn is_valid(mut numbers: Vec<i32>)
    -> bool
{
    if numbers.len() != 3
    {
        return false;
    }
    numbers.sort();
    return numbers[0] >= 0 && numbers[0] + numbers[1] > numbers[2];
}

fn main()
{
    let stdin = io::stdin();
    let mut n_possible = 0;
    for line in stdin.lock().lines()
    {
        let mut numbers = get_numbers(line.unwrap());
        if is_valid(numbers)
        {
            n_possible += 1;
        }
    }
    println!("{}", n_possible);
}
<commit_msg>Debug print<commit_after>mod advent_of_code;

use advent_of_code::get_numbers;

use std::io;
use std::io::BufRead;

fn is_valid(mut numbers: Vec<i32>)
    -> bool
{
    if numbers.len() != 3
    {
        return false;
    }
    numbers.sort();
    return numbers[0] >= 0 && numbers[0] + numbers[1] > numbers[2];
}

fn main()
{
    let stdin = io::stdin();
    let mut n_possible = 0;
    for line in stdin.lock().lines()
    {
        let mut numbers = get_numbers(line.unwrap());
        //println!("{:?}", numbers);
        if is_valid(numbers)
        {
            n_possible += 1;
        }
    }
    println!("{}", n_possible);
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate clap;
extern crate dotenv;
extern crate error;
extern crate fs2;
#[macro_use]
extern crate libproto;
#[macro_use]
extern crate logger;
extern crate pubsub;
#[macro_use]
extern crate util;

use clap::App;
use fs2::FileExt;
use libproto::router::{MsgType, RoutingKey, SubModules};
use postman::Postman;
use pubsub::channel;
use pubsub::start_pubsub;
use std::fs::{self, File, OpenOptions};
use util::set_panic_handler;

mod postman;

const SNAPSHOT_LOCK: &str = ".cita_snapshot";

fn main() {
    micro_service_init!("cita-snapshot", "CITA:snapshot", false);

    // 1. Aquire client's lock
    let locker = lock();

    // 2. Parse command-line options
    let matches = App::new("snapshot")
        .version("2.0")
        .author("Cryptape")
        .about("CITA Block Chain Node powered by Rust")
        .arg_from_usage("-m, --cmd=[snapshot] 'snapshot or restore'")
        .arg_from_usage("-f, --file=[snapshot] 'the file of snapshot'") //snap file path
        .arg_from_usage("-s, --start_height=[0] 'start height'") //latest or valid ancient block_id
        .arg_from_usage("-e, --end_height=[1000] 'end height'") //todo remove
        .get_matches();
    let command = matches.value_of("cmd").expect("provide specific command");
    let command = cast_command(command);
    let file = matches
        .value_of("file")
        .expect("provice specific snapshot-file path");
    let file = file.to_owned();
    let start_height = matches.value_of("start_height").unwrap_or("0");
    let start_height = cast_height(start_height);
    let end_height = matches.value_of("end_height").unwrap_or("0");
    let end_height = cast_height(end_height);

    // 3. Start message-bus watcher in background
    let (mq_req_sender, mq_req_receiver) = channel::unbounded();
    let (mq_resp_sender, mq_resp_receiver) = channel::unbounded();
    start_pubsub(
        "snapshot",
        routing_key!([
            Net >> SnapshotResp,
            Consensus >> SnapshotResp,
            Executor >> SnapshotResp,
            Chain >> SnapshotResp,
            Auth >> SnapshotResp,
        ]),
        mq_req_sender,
        mq_resp_receiver,
    );

    // 4. Create a postman and start serving
    let mut postman = Postman::new(
        mq_req_receiver,
        mq_resp_sender,
        command,
        start_height,
        end_height,
        file,
    );
    postman.clear_message_bus();
    match postman.serve() {
        Ok(()) => info!("successful to {}", postman.command),
        Err(err) => error!("failed to {}: {:?}", postman.command, err),
    }

    // 5. Release client's lock
    unlock(&locker);
}

fn lock() -> File {
    let locker = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(SNAPSHOT_LOCK)
        .unwrap_or_else(|_| panic!("failed to open lock-file {}", SNAPSHOT_LOCK));
    locker
        .try_lock_exclusive()
        .expect("snapshot already started.");
    locker
}

fn unlock(locker: &File) {
    locker.unlock().unwrap();
    fs::remove_file(SNAPSHOT_LOCK).expect("failed to release lock-file");
}

fn cast_command(command: &str) -> String {
    assert!(
        command == "snapshot" || command == "restore",
        "given command is equal either snapshot or restore: {}",
        command,
    );
    command.to_string()
}

fn cast_height(s: &str) -> u64 {
    if s.starts_with("0x") || s.starts_with("0X") {
        u64::from_str_radix(&s[2..], 16).unwrap()
    } else {
        u64::from_str_radix(s, 10).unwrap()
    }
}
<commit_msg>fix panic in snapshot path[skip travis]<commit_after>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate clap;
extern crate dotenv;
extern crate error;
extern crate fs2;
#[macro_use]
extern crate libproto;
#[macro_use]
extern crate logger;
extern crate pubsub;
#[macro_use]
extern crate util;

use clap::App;
use fs2::FileExt;
use libproto::router::{MsgType, RoutingKey, SubModules};
use postman::Postman;
use pubsub::channel;
use pubsub::start_pubsub;
use std::fs::{self, File, OpenOptions};
use util::set_panic_handler;

mod postman;

const SNAPSHOT_LOCK: &str = ".cita_snapshot";

fn main() {
    micro_service_init!("cita-snapshot", "CITA:snapshot", false);

    // 1. Aquire client's lock
    let locker = lock();

    // 2. Parse command-line options
    let matches = App::new("snapshot")
        .version("2.0")
        .author("Cryptape")
        .about("CITA Block Chain Node powered by Rust")
        .arg_from_usage("-m, --cmd=[snapshot] 'snapshot or restore'")
        .arg_from_usage("-f, --file=[snapshot] 'the file of snapshot'") //snap file path
        .arg_from_usage("-s, --start_height=[0] 'start height'") //latest or valid ancient block_id
        .arg_from_usage("-e, --end_height=[1000] 'end height'") //todo remove
        .get_matches();
    let command = matches.value_of("cmd").expect("provide specific command");
    let command = cast_command(command);
    let file = matches.value_of("file").unwrap_or("snapshot");
    let file = file.to_owned();
    let start_height = matches.value_of("start_height").unwrap_or("0");
    let start_height = cast_height(start_height);
    let end_height = matches.value_of("end_height").unwrap_or("0");
    let end_height = cast_height(end_height);

    // 3. Start message-bus watcher in background
    let (mq_req_sender, mq_req_receiver) = channel::unbounded();
    let (mq_resp_sender, mq_resp_receiver) = channel::unbounded();
    start_pubsub(
        "snapshot",
        routing_key!([
            Net >> SnapshotResp,
            Consensus >> SnapshotResp,
            Executor >> SnapshotResp,
            Chain >> SnapshotResp,
            Auth >> SnapshotResp,
        ]),
        mq_req_sender,
        mq_resp_receiver,
    );

    // 4. Create a postman and start serving
    let mut postman = Postman::new(
        mq_req_receiver,
        mq_resp_sender,
        command,
        start_height,
        end_height,
        file,
    );
    postman.clear_message_bus();
    match postman.serve() {
        Ok(()) => info!("successful to {}", postman.command),
        Err(err) => error!("failed to {}: {:?}", postman.command, err),
    }

    // 5. Release client's lock
    unlock(&locker);
}

fn lock() -> File {
    let locker = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(SNAPSHOT_LOCK)
        .unwrap_or_else(|_| panic!("failed to open lock-file {}", SNAPSHOT_LOCK));
    locker
        .try_lock_exclusive()
        .expect("snapshot already started.");
    locker
}

fn unlock(locker: &File) {
    locker.unlock().unwrap();
    fs::remove_file(SNAPSHOT_LOCK).expect("failed to release lock-file");
}

fn cast_command(command: &str) -> String {
    assert!(
        command == "snapshot" || command == "restore",
        "given command is equal either snapshot or restore: {}",
        command,
    );
    command.to_string()
}

fn cast_height(s: &str) -> u64 {
    if s.starts_with("0x") || s.starts_with("0X") {
        u64::from_str_radix(&s[2..], 16).unwrap()
    } else {
        u64::from_str_radix(s, 10).unwrap()
    }
}
<|endoftext|>


<commit_before>use libc::c_int;

// sym corresponds to the `key` enum, mod_ to the mod_ enum. We should
// be using the correct type here but our enums don't have the right
// size yet
type KeySym = {
    scancode: u8,
    sym: c_int,
    mod_: c_int,
    unicode: u16
};

/** What we really want is a mapping of every raw key on the keyboard.
 *  To support international keyboards, we use the range 0xA1 - 0xFF
 *  as international virtual keycodes.  We'll follow in the footsteps of X11...
 *  @brief The names of the keys
 */
enum Key {
    /** @name ASCII mapped KeySyms
    *  The keyboard syms have been cleverly chosen to map to ASCII
    */
    /*@{*/
    SDLK_UNKNOWN		= 0,
    //SDLK_FIRST		= 0,
    SDLK_BACKSPACE		= 8,
    SDLK_TAB		= 9,
    SDLK_CLEAR		= 12,
    SDLK_RETURN		= 13,
    SDLK_PAUSE		= 19,
    SDLK_ESCAPE		= 27,
    SDLK_SPACE		= 32,
    SDLK_EXCLAIM		= 33,
    SDLK_QUOTEDBL		= 34,
    SDLK_HASH		= 35,
    SDLK_DOLLAR		= 36,
    SDLK_AMPERSAND		= 38,
    SDLK_QUOTE		= 39,
    SDLK_LEFTPAREN		= 40,
    SDLK_RIGHTPAREN		= 41,
    SDLK_ASTERISK		= 42,
    SDLK_PLUS		= 43,
    SDLK_COMMA		= 44,
    SDLK_MINUS		= 45,
    SDLK_PERIOD		= 46,
    SDLK_SLASH		= 47,
    SDLK_0			= 48,
    SDLK_1			= 49,
    SDLK_2			= 50,
    SDLK_3			= 51,
    SDLK_4			= 52,
    SDLK_5			= 53,
    SDLK_6			= 54,
    SDLK_7			= 55,
    SDLK_8			= 56,
    SDLK_9			= 57,
    SDLK_COLON		= 58,
    SDLK_SEMICOLON		= 59,
    SDLK_LESS		= 60,
    SDLK_EQUALS		= 61,
    SDLK_GREATER		= 62,
    SDLK_QUESTION		= 63,
    SDLK_AT			= 64,
    /*
    Skip uppercase letters
    */
    SDLK_LEFTBRACKET	= 91,
    SDLK_BACKSLASH		= 92,
    SDLK_RIGHTBRACKET	= 93,
    SDLK_CARET		= 94,
    SDLK_UNDERSCORE		= 95,
    SDLK_BACKQUOTE		= 96,
    SDLK_a			= 97,
    SDLK_b			= 98,
    SDLK_c			= 99,
    SDLK_d			= 100,
    SDLK_e			= 101,
    SDLK_f			= 102,
    SDLK_g			= 103,
    SDLK_h			= 104,
    SDLK_i			= 105,
    SDLK_j			= 106,
    SDLK_k			= 107,
    SDLK_l			= 108,
    SDLK_m			= 109,
    SDLK_n			= 110,
    SDLK_o			= 111,
    SDLK_p			= 112,
    SDLK_q			= 113,
    SDLK_r			= 114,
    SDLK_s			= 115,
    SDLK_t			= 116,
    SDLK_u			= 117,
    SDLK_v			= 118,
    SDLK_w			= 119,
    SDLK_x			= 120,
    SDLK_y			= 121,
    SDLK_z			= 122,
    SDLK_DELETE		= 127,
    /* End of ASCII mapped KeySyms */
    /*@}*/

    /** @name International keyboard syms */
    /*@{*/
    SDLK_WORLD_0		= 160,		/* 0xA0 */
    SDLK_WORLD_1		= 161,
    SDLK_WORLD_2		= 162,
    SDLK_WORLD_3		= 163,
    SDLK_WORLD_4		= 164,
    SDLK_WORLD_5		= 165,
    SDLK_WORLD_6		= 166,
    SDLK_WORLD_7		= 167,
    SDLK_WORLD_8		= 168,
    SDLK_WORLD_9		= 169,
    SDLK_WORLD_10		= 170,
    SDLK_WORLD_11		= 171,
    SDLK_WORLD_12		= 172,
    SDLK_WORLD_13		= 173,
    SDLK_WORLD_14		= 174,
    SDLK_WORLD_15		= 175,
    SDLK_WORLD_16		= 176,
    SDLK_WORLD_17		= 177,
    SDLK_WORLD_18		= 178,
    SDLK_WORLD_19		= 179,
    SDLK_WORLD_20		= 180,
    SDLK_WORLD_21		= 181,
    SDLK_WORLD_22		= 182,
    SDLK_WORLD_23		= 183,
    SDLK_WORLD_24		= 184,
    SDLK_WORLD_25		= 185,
    SDLK_WORLD_26		= 186,
    SDLK_WORLD_27		= 187,
    SDLK_WORLD_28		= 188,
    SDLK_WORLD_29		= 189,
    SDLK_WORLD_30		= 190,
    SDLK_WORLD_31		= 191,
    SDLK_WORLD_32		= 192,
    SDLK_WORLD_33		= 193,
    SDLK_WORLD_34		= 194,
    SDLK_WORLD_35		= 195,
    SDLK_WORLD_36		= 196,
    SDLK_WORLD_37		= 197,
    SDLK_WORLD_38		= 198,
    SDLK_WORLD_39		= 199,
    SDLK_WORLD_40		= 200,
    SDLK_WORLD_41		= 201,
    SDLK_WORLD_42		= 202,
    SDLK_WORLD_43		= 203,
    SDLK_WORLD_44		= 204,
    SDLK_WORLD_45		= 205,
    SDLK_WORLD_46		= 206,
    SDLK_WORLD_47		= 207,
    SDLK_WORLD_48		= 208,
    SDLK_WORLD_49		= 209,
    SDLK_WORLD_50		= 210,
    SDLK_WORLD_51		= 211,
    SDLK_WORLD_52		= 212,
    SDLK_WORLD_53		= 213,
    SDLK_WORLD_54		= 214,
    SDLK_WORLD_55		= 215,
    SDLK_WORLD_56		= 216,
    SDLK_WORLD_57		= 217,
    SDLK_WORLD_58		= 218,
    SDLK_WORLD_59		= 219,
    SDLK_WORLD_60		= 220,
    SDLK_WORLD_61		= 221,
    SDLK_WORLD_62		= 222,
    SDLK_WORLD_63		= 223,
    SDLK_WORLD_64		= 224,
    SDLK_WORLD_65		= 225,
    SDLK_WORLD_66		= 226,
    SDLK_WORLD_67		= 227,
    SDLK_WORLD_68		= 228,
    SDLK_WORLD_69		= 229,
    SDLK_WORLD_70		= 230,
    SDLK_WORLD_71		= 231,
    SDLK_WORLD_72		= 232,
    SDLK_WORLD_73		= 233,
    SDLK_WORLD_74		= 234,
    SDLK_WORLD_75		= 235,
    SDLK_WORLD_76		= 236,
    SDLK_WORLD_77		= 237,
    SDLK_WORLD_78		= 238,
    SDLK_WORLD_79		= 239,
    SDLK_WORLD_80		= 240,
    SDLK_WORLD_81		= 241,
    SDLK_WORLD_82		= 242,
    SDLK_WORLD_83		= 243,
    SDLK_WORLD_84		= 244,
    SDLK_WORLD_85		= 245,
    SDLK_WORLD_86		= 246,
    SDLK_WORLD_87		= 247,
    SDLK_WORLD_88		= 248,
    SDLK_WORLD_89		= 249,
    SDLK_WORLD_90		= 250,
    SDLK_WORLD_91		= 251,
    SDLK_WORLD_92		= 252,
    SDLK_WORLD_93		= 253,
    SDLK_WORLD_94		= 254,
    SDLK_WORLD_95		= 255,		/* 0xFF */
    /*@}*/

    /** @name Numeric keypad */
    /*@{*/
    SDLK_KP0		= 256,
    SDLK_KP1		= 257,
    SDLK_KP2		= 258,
    SDLK_KP3		= 259,
    SDLK_KP4		= 260,
    SDLK_KP5		= 261,
    SDLK_KP6		= 262,
    SDLK_KP7		= 263,
    SDLK_KP8		= 264,
    SDLK_KP9		= 265,
    SDLK_KP_PERIOD		= 266,
    SDLK_KP_DIVIDE		= 267,
    SDLK_KP_MULTIPLY	= 268,
    SDLK_KP_MINUS		= 269,
    SDLK_KP_PLUS		= 270,
    SDLK_KP_ENTER		= 271,
    SDLK_KP_EQUALS		= 272,
    /*@}*/

    /** @name Arrows + Home/End pad */
    /*@{*/
    SDLK_UP			= 273,
    SDLK_DOWN		= 274,
    SDLK_RIGHT		= 275,
    SDLK_LEFT		= 276,
    SDLK_INSERT		= 277,
    SDLK_HOME		= 278,
    SDLK_END		= 279,
    SDLK_PAGEUP		= 280,
    SDLK_PAGEDOWN		= 281,
    /*@}*/

    /** @name Function keys */
    /*@{*/
    SDLK_F1			= 282,
    SDLK_F2			= 283,
    SDLK_F3			= 284,
    SDLK_F4			= 285,
    SDLK_F5			= 286,
    SDLK_F6			= 287,
    SDLK_F7			= 288,
    SDLK_F8			= 289,
    SDLK_F9			= 290,
    SDLK_F10		= 291,
    SDLK_F11		= 292,
    SDLK_F12		= 293,
    SDLK_F13		= 294,
    SDLK_F14		= 295,
    SDLK_F15		= 296,
    /*@}*/

    /** @name Key state modifier keys */
    /*@{*/
    SDLK_NUMLOCK		= 300,
    SDLK_CAPSLOCK		= 301,
    SDLK_SCROLLOCK		= 302,
    SDLK_RSHIFT		= 303,
    SDLK_LSHIFT		= 304,
    SDLK_RCTRL		= 305,
    SDLK_LCTRL		= 306,
    SDLK_RALT		= 307,
    SDLK_LALT		= 308,
    SDLK_RMETA		= 309,
    SDLK_LMETA		= 310,
    SDLK_LSUPER		= 311,		/**< Left "Windows" key */
    SDLK_RSUPER		= 312,		/**< Right "Windows" key */
    SDLK_MODE		= 313,		/**< "Alt Gr" key */
    SDLK_COMPOSE		= 314,		/**< Multi-key compose key */
    /*@}*/

    /** @name Miscellaneous function keys */
    /*@{*/
    SDLK_HELP		= 315,
    SDLK_PRINT		= 316,
    SDLK_SYSREQ		= 317,
    SDLK_BREAK		= 318,
    SDLK_MENU		= 319,
    SDLK_POWER		= 320,		/**< Power Macintosh power key */
    SDLK_EURO		= 321,		/**< Some european keyboards */
    SDLK_UNDO		= 322,		/**< Atari keyboard has Undo */
    /*@}*/

    /* Add any other keys here */

    SDLK_LAST
}

/** Enumeration of valid key mods (possibly OR'd together) */
enum mod_ {
	KMOD_NONE  = 0x0000,
	KMOD_LSHIFT= 0x0001,
	KMOD_RSHIFT= 0x0002,
	KMOD_LCTRL = 0x0040,
	KMOD_RCTRL = 0x0080,
	KMOD_LALT  = 0x0100,
	KMOD_RALT  = 0x0200,
	KMOD_LMETA = 0x0400,
	KMOD_RMETA = 0x0800,
	KMOD_NUM   = 0x1000,
	KMOD_CAPS  = 0x2000,
	KMOD_MODE  = 0x4000,
	KMOD_RESERVED = 0x8000
}
<commit_msg>Updated to be camelcased - compiler's no longer shouting angry warnings<commit_after>use libc::c_int;

// sym corresponds to the `Key` enum, mod_ to the `Mod` enum. We should
// be using the correct type here but our enums don't have the right
// size yet
type KeySym = {
    scancode: u8,
    sym: c_int,
    mod_: c_int,
    unicode: u16
};

/** What we really want is a mapping of every raw key on the keyboard.
 *  To support international keyboards, we use the range 0xA1 - 0xFF
 *  as international virtual keycodes.  We'll follow in the footsteps of X11...
 *  @brief The names of the keys
 */
enum Key {
    /** @name ASCII mapped KeySyms
    *  The keyboard syms have been cleverly chosen to map to ASCII
    */
    /*@{*/
    SDLKUnknown         = 0,
    //SDLKFirst         = 0,
    SDLKBackspace       = 8,
    SDLKTab             = 9,
    SDLKClear           = 12,
    SDLKReturn          = 13,
    SDLKPause           = 19,
    SDLKEscape          = 27,
    SDLKSpace           = 32,
    SDLKExclaim         = 33,
    SDLKQuotedbl        = 34,
    SDLKHash            = 35,
    SDLKDollar          = 36,
    SDLKAmpersand       = 38,
    SDLKQuote           = 39,
    SDLKLeftParen       = 40,
    SDLKRightParen      = 41,
    SDLKAsterisk        = 42,
    SDLKPlus            = 43,
    SDLKComma           = 44,
    SDLKMinus           = 45,
    SDLKPeriod          = 46,
    SDLKSlash           = 47,
    SDLK0               = 48,
    SDLK1               = 49,
    SDLK2               = 50,
    SDLK3               = 51,
    SDLK4               = 52,
    SDLK5               = 53,
    SDLK6               = 54,
    SDLK7               = 55,
    SDLK8               = 56,
    SDLK9               = 57,
    SDLKColon           = 58,
    SDLKSemicolon       = 59,
    SDLKLess            = 60,
    SDLKEquals          = 61,
    SDLKGreater         = 62,
    SDLKQuestion        = 63,
    SDLKAt              = 64,
    /*
    Skip uppercase letters
    */
    SDLKLeftBracket     = 91,
    SDLKBackslash       = 92,
    SDLKRightBracket    = 93,
    SDLKCaret           = 94,
    SDLKUnderscore      = 95,
    SDLKBackquote       = 96,
    SDLKa               = 97,
    SDLKb               = 98,
    SDLKc               = 99,
    SDLKd               = 100,
    SDLKe               = 101,
    SDLKf               = 102,
    SDLKg               = 103,
    SDLKh               = 104,
    SDLKi               = 105,
    SDLKj               = 106,
    SDLKk               = 107,
    SDLKl               = 108,
    SDLKm               = 109,
    SDLKn               = 110,
    SDLKo               = 111,
    SDLKp               = 112,
    SDLKq               = 113,
    SDLKr               = 114,
    SDLKs               = 115,
    SDLKt               = 116,
    SDLKu               = 117,
    SDLKv               = 118,
    SDLKw               = 119,
    SDLKx               = 120,
    SDLKy               = 121,
    SDLKz               = 122,
    SDLKDelete          = 127,
    /* End of ASCII mapped KeySyms */
    /*@}*/

    /** @name International keyboard syms */
    /*@{*/
    SDLKWorld0          = 160,      /* 0xA0 */
    SDLKWorld1          = 161,
    SDLKWorld2          = 162,
    SDLKWorld3          = 163,
    SDLKWorld4          = 164,
    SDLKWorld5          = 165,
    SDLKWorld6          = 166,
    SDLKWorld7          = 167,
    SDLKWorld8          = 168,
    SDLKWorld9          = 169,
    SDLKWorld10         = 170,
    SDLKWorld11         = 171,
    SDLKWorld12         = 172,
    SDLKWorld13         = 173,
    SDLKWorld14         = 174,
    SDLKWorld15         = 175,
    SDLKWorld16         = 176,
    SDLKWorld17         = 177,
    SDLKWorld18         = 178,
    SDLKWorld19         = 179,
    SDLKWorld20         = 180,
    SDLKWorld21         = 181,
    SDLKWorld22         = 182,
    SDLKWorld23         = 183,
    SDLKWorld24         = 184,
    SDLKWorld25         = 185,
    SDLKWorld26         = 186,
    SDLKWorld27         = 187,
    SDLKWorld28         = 188,
    SDLKWorld29         = 189,
    SDLKWorld30         = 190,
    SDLKWorld31         = 191,
    SDLKWorld32         = 192,
    SDLKWorld33         = 193,
    SDLKWorld34         = 194,
    SDLKWorld35         = 195,
    SDLKWorld36         = 196,
    SDLKWorld37         = 197,
    SDLKWorld38         = 198,
    SDLKWorld39         = 199,
    SDLKWorld40         = 200,
    SDLKWorld41         = 201,
    SDLKWorld42         = 202,
    SDLKWorld43         = 203,
    SDLKWorld44         = 204,
    SDLKWorld45         = 205,
    SDLKWorld46         = 206,
    SDLKWorld47         = 207,
    SDLKWorld48         = 208,
    SDLKWorld49         = 209,
    SDLKWorld50         = 210,
    SDLKWorld51         = 211,
    SDLKWorld52         = 212,
    SDLKWorld53         = 213,
    SDLKWorld54         = 214,
    SDLKWorld55         = 215,
    SDLKWorld56         = 216,
    SDLKWorld57         = 217,
    SDLKWorld58         = 218,
    SDLKWorld59         = 219,
    SDLKWorld60         = 220,
    SDLKWorld61         = 221,
    SDLKWorld62         = 222,
    SDLKWorld63         = 223,
    SDLKWorld64         = 224,
    SDLKWorld65         = 225,
    SDLKWorld66         = 226,
    SDLKWorld67         = 227,
    SDLKWorld68         = 228,
    SDLKWorld69         = 229,
    SDLKWorld70         = 230,
    SDLKWorld71         = 231,
    SDLKWorld72         = 232,
    SDLKWorld73         = 233,
    SDLKWorld74         = 234,
    SDLKWorld75         = 235,
    SDLKWorld76         = 236,
    SDLKWorld77         = 237,
    SDLKWorld78         = 238,
    SDLKWorld79         = 239,
    SDLKWorld80         = 240,
    SDLKWorld81         = 241,
    SDLKWorld82         = 242,
    SDLKWorld83         = 243,
    SDLKWorld84         = 244,
    SDLKWorld85         = 245,
    SDLKWorld86         = 246,
    SDLKWorld87         = 247,
    SDLKWorld88         = 248,
    SDLKWorld89         = 249,
    SDLKWorld90         = 250,
    SDLKWorld91         = 251,
    SDLKWorld92         = 252,
    SDLKWorld93         = 253,
    SDLKWorld94         = 254,
    SDLKWorld95         = 255,      /* 0xFF */
    /*@}*/

    /** @name Numeric keypad */
    /*@{*/
    SDLKKp0             = 256,
    SDLKKp1             = 257,
    SDLKKp2             = 258,
    SDLKKp3             = 259,
    SDLKKp4             = 260,
    SDLKKp5             = 261,
    SDLKKp6             = 262,
    SDLKKp7             = 263,
    SDLKKp8             = 264,
    SDLKKp9             = 265,
    SDLKKpPeriod        = 266,
    SDLKKpDivide        = 267,
    SDLKKpMultiply      = 268,
    SDLKKpMinus         = 269,
    SDLKKpPlus          = 270,
    SDLKKpEnter         = 271,
    SDLKKpEquals        = 272,
    /*@}*/

    /** @name Arrows + Home/End pad */
    /*@{*/
    SDLKUp              = 273,
    SDLKDown            = 274,
    SDLKRight           = 275,
    SDLKLeft            = 276,
    SDLKInsert          = 277,
    SDLKHome            = 278,
    SDLKEnd             = 279,
    SDLKPageUp          = 280,
    SDLKPageDown        = 281,
    /*@}*/

    /** @name Function keys */
    /*@{*/
    SDLKF1              = 282,
    SDLKF2              = 283,
    SDLKF3              = 284,
    SDLKF4              = 285,
    SDLKF5              = 286,
    SDLKF6              = 287,
    SDLKF7              = 288,
    SDLKF8              = 289,
    SDLKF9              = 290,
    SDLKF10             = 291,
    SDLKF11             = 292,
    SDLKF12             = 293,
    SDLKF13             = 294,
    SDLKF14             = 295,
    SDLKF15             = 296,
    /*@}*/

    /** @name Key state modifier keys */
    /*@{*/
    SDLKNumLock         = 300,
    SDLKCapsLock        = 301,
    SDLKScrolLock       = 302,
    SDLKRShift          = 303,
    SDLKLShift          = 304,
    SDLKRCtrl           = 305,
    SDLKLCtrl           = 306,
    SDLKRAlt            = 307,
    SDLKLAlt            = 308,
    SDLKRMeta           = 309,
    SDLKLMeta           = 310,
    SDLKLSuper          = 311,      /**< Left "Windows" key */
    SDLKRSuper          = 312,      /**< Right "Windows" key */
    SDLKMode            = 313,      /**< "Alt Gr" key */
    SDLKCompose         = 314,      /**< Multi-key compose key */
    /*@}*/

    /** @name Miscellaneous function keys */
    /*@{*/
    SDLKHelp            = 315,
    SDLKPrint           = 316,
    SDLKSysReq          = 317,
    SDLKBreak           = 318,
    SDLKMenu            = 319,
    SDLKPower           = 320,      /**< Power Macintosh power key */
    SDLKEuro            = 321,      /**< Some european keyboards */
    SDLKUndo            = 322,      /**< Atari keyboard has Undo */
    /*@}*/

    /* Add any other keys here */

    SDLKLast
}

/** Enumeration of valid key mods (possibly OR'd together) */
enum Mod {
    KMODNone            = 0x0000,
    KMODLShift          = 0x0001,
    KMODRShift          = 0x0002,
    KMODLCtrl           = 0x0040,
    KMODRCtrl           = 0x0080,
    KMODLAlt            = 0x0100,
    KMODRAlt            = 0x0200,
    KMODLMeta           = 0x0400,
    KMODRMeta           = 0x0800,
    KMODNum             = 0x1000,
    KMODCaps            = 0x2000,
    KMODMode            = 0x4000,
    KMODReserved        = 0x8000
}
<|endoftext|>