<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! The executor runs all given futures to completion. Futures register wakers associated with file
//! descriptors. The wakers will be called when the FD becomes readable or writable depending on
//! the situation.
//!
//! `FdExecutor` is meant to be used with the `futures-rs` crate that provides combinators and
//! utility functions to combine futures.

use std::cell::RefCell;
use std::collections::{BTreeMap, VecDeque};
use std::fmt::{self, Display};
use std::fs::File;
use std::future::Future;
use std::os::unix::io::FromRawFd;
use std::os::unix::io::RawFd;
use std::pin::Pin;
use std::task::Waker;

use sys_util::{PollContext, WatchingEvents};

use crate::executor::{ExecutableFuture, Executor, FutureList, WakerToken};

#[derive(Debug, PartialEq)]
pub enum Error {
    /// Attempts to create two Executors on the same thread fail.
    AttemptedDuplicateExecutor,
    /// Failed to copy the FD for the polling context.
    DuplicatingFd(sys_util::Error),
    /// Failed accessing the thread local storage for wakers.
    InvalidContext,
    /// Creating a context to wait on FDs failed.
    CreatingContext(sys_util::Error),
    /// PollContext failure.
    PollContextError(sys_util::Error),
    /// Failed to submit the waker to the polling context.
    SubmittingWaker(sys_util::Error),
}
pub type Result<T> = std::result::Result<T, Error>;

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            AttemptedDuplicateExecutor => write!(f, "Cannot have two executors on one thread."),
            DuplicatingFd(e) => write!(f, "Failed to copy the FD for the polling context: {}", e),
            InvalidContext => write!(
                f,
                "Invalid context, was the Fd executor created successfully?"
            ),
            CreatingContext(e) => write!(f, "An error creating the fd waiting context: {}.", e),
            PollContextError(e) => write!(f, "PollContext failure: {}", e),
            SubmittingWaker(e) => write!(f, "An error adding to the Aio context: {}.", e),
        }
    }
}

// Temporary vectors of new additions to the executor.

// Tracks active wakers and the futures they are associated with.
thread_local!(static STATE: RefCell<Option<FdWakerState>> = RefCell::new(None));

fn add_waker(fd: RawFd, waker: Waker, events: WatchingEvents) -> Result<WakerToken> {
    STATE.with(|state| {
        let mut state = state.borrow_mut();
        if let Some(state) = state.as_mut() {
            state.add_waker(fd, waker, events)
        } else {
            Err(Error::InvalidContext)
        }
    })
}

/// Tells the waking system to wake `waker` when `fd` becomes readable.
/// The 'fd' must be fully owned by the future adding the waker, and must not be closed until the
/// next time the future is polled. If the fd is closed, there is a race where another FD can be
/// opened on top of it causing the next poll to access the new target file.
/// Returns a `WakerToken` that can be used to cancel the waker before it completes.
pub fn add_read_waker(fd: RawFd, waker: Waker) -> Result<WakerToken> {
    add_waker(fd, waker, WatchingEvents::empty().set_read())
}

/// Tells the waking system to wake `waker` when `fd` becomes writable.
/// The 'fd' must be fully owned by the future adding the waker, and must not be closed until the
/// next time the future is polled. If the fd is closed, there is a race where another FD can be
/// opened on top of it causing the next poll to access the new target file.
/// Returns a `WakerToken` that can be used to cancel the waker before it completes.
pub fn add_write_waker(fd: RawFd, waker: Waker) -> Result<WakerToken> {
    add_waker(fd, waker, WatchingEvents::empty().set_write())
}

/// Cancels the waker that returned the given token if the waker hasn't yet fired.
pub fn cancel_waker(token: WakerToken) -> Result<()> {
    STATE.with(|state| {
        let mut state = state.borrow_mut();
        if let Some(state) = state.as_mut() {
            state.cancel_waker(token)
        } else {
            Err(Error::InvalidContext)
        }
    })
}

/// Adds a new top level future to the Executor.
/// These futures must return `()`, indicating they are intended to create side-effects only.
pub fn add_future(future: Pin<Box<dyn Future<Output = ()>>>) -> Result<()> {
    STATE.with(|state| {
        let mut state = state.borrow_mut();
        if let Some(state) = state.as_mut() {
            state.new_futures.push_back(ExecutableFuture::new(future));
            Ok(())
        } else {
            Err(Error::InvalidContext)
        }
    })
}

// Tracks active wakers and associates wakers with the futures that registered them.
struct FdWakerState {
    poll_ctx: PollContext<u64>,
    token_map: BTreeMap<u64, (File, Waker)>,
    next_token: u64, // Next token for adding to the context.
    new_futures: VecDeque<ExecutableFuture<()>>,
}

impl FdWakerState {
    fn new() -> Result<Self> {
        Ok(FdWakerState {
            poll_ctx: PollContext::new().map_err(Error::CreatingContext)?,
            token_map: BTreeMap::new(),
            next_token: 0,
            new_futures: VecDeque::new(),
        })
    }

    // Adds an fd that, when signaled, will trigger the given waker.
    fn add_waker(&mut self, fd: RawFd, waker: Waker, events: WatchingEvents) -> Result<WakerToken> {
        let duped_fd = unsafe {
            // Safe because duplicating an FD doesn't affect memory safety, and the dup'd FD
            // will only be added to the poll loop.
            File::from_raw_fd(dup_fd(fd)?)
        };
        self.poll_ctx
            .add_fd_with_events(&duped_fd, events, self.next_token)
            .map_err(Error::SubmittingWaker)?;
        let next_token = self.next_token;
        self.token_map.insert(next_token, (duped_fd, waker));
        self.next_token += 1;
        Ok(WakerToken(next_token))
    }

    // Waits until one of the FDs is readable and wakes the associated waker.
    fn wait_wake_event(&mut self) -> Result<()> {
        let events = self.poll_ctx.wait().map_err(Error::PollContextError)?;
        for e in events.iter() {
            if let Some((fd, waker)) = self.token_map.remove(&e.token()) {
                self.poll_ctx.delete(&fd).map_err(Error::PollContextError)?;
                waker.wake_by_ref();
            }
        }
        Ok(())
    }

    // Remove the waker for the given token if it hasn't fired yet.
    fn cancel_waker(&mut self, token: WakerToken) -> Result<()> {
        if let Some((fd, _waker)) = self.token_map.remove(&token.0) {
            self.poll_ctx.delete(&fd).map_err(Error::PollContextError)?;
        }
        Ok(())
    }
}

/// Runs futures to completion on a single thread. Futures are allowed to block on file descriptors
/// only. Futures can only block on FDs becoming readable or writable. `FdExecutor` is meant to be
/// used where a poll or select loop would be used otherwise.
pub(crate) struct FdExecutor<T: FutureList> {
    futures: T,
}

impl<T: FutureList> Executor for FdExecutor<T> {
    type Output = Result<T::Output>;

    fn run(&mut self) -> Self::Output {
        self.append_futures();

        loop {
            if let Some(output) = self.futures.poll_results() {
                return Ok(output);
            }

            self.append_futures();

            // If no futures are ready, sleep until a waker is signaled.
            if !self.futures.any_ready() {
                STATE.with(|state| {
                    let mut state = state.borrow_mut();
                    if let Some(state) = state.as_mut() {
                        state.wait_wake_event()?;
                    } else {
                        unreachable!("Can't get here without a context being created");
                    }
                    Ok(())
                })?;
            }
        }
    }
}

impl<T: FutureList> FdExecutor<T> {
    /// Create a new executor.
    pub fn new(futures: T) -> Result<FdExecutor<T>> {
        STATE.with(|state| {
            if state.borrow().is_some() {
                return Err(Error::AttemptedDuplicateExecutor);
            }
            state.replace(Some(FdWakerState::new()?));
            Ok(())
        })?;
        Ok(FdExecutor { futures })
    }

    // Add any new futures and wakers to the lists.
    fn append_futures(&mut self) {
        STATE.with(|state| {
            let mut state = state.borrow_mut();
            if let Some(state) = state.as_mut() {
                self.futures.futures_mut().append(&mut state.new_futures);
            } else {
                unreachable!("Can't get here without a context being created");
            }
        });
    }
}

impl<T: FutureList> Drop for FdExecutor<T> {
    fn drop(&mut self) {
        STATE.with(|state| {
            state.replace(None);
        });
    }
}

// Used to dup the FDs passed to the executor so there is a guarantee they aren't closed while
// waiting in TLS to be added to the main polling context.
unsafe fn dup_fd(fd: RawFd) -> Result<RawFd> {
    let ret = libc::dup(fd);
    if ret < 0 {
        Err(Error::DuplicatingFd(sys_util::Error::last()))
    } else {
        Ok(ret)
    }
}

#[cfg(test)]
mod test {
    use std::cell::RefCell;
    use std::future::Future;
    use std::os::unix::io::AsRawFd;
    use std::rc::Rc;
    use std::task::{Context, Poll};

    use futures::future::Either;
    use futures::pin_mut;

    use super::*;

    struct TestFut {
        f: File,
        token: Option<WakerToken>,
    }

    impl TestFut {
        fn new(f: File) -> TestFut {
            TestFut { f, token: None }
        }
    }

    impl Future for TestFut {
        type Output = u64;
        fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
            if self.token.is_none() {
                self.token = Some(add_read_waker(self.f.as_raw_fd(), cx.waker().clone()).unwrap());
            }
            Poll::Pending
        }
    }

    impl Drop for TestFut {
        fn drop(&mut self) {
            if let Some(token) = self.token.take() {
                cancel_waker(token).unwrap();
            }
        }
    }

    #[test]
    fn cancel() {
        async fn do_test() {
            let (r, _w) = sys_util::pipe(true).unwrap();
            let done = async { 5usize };
            let pending = TestFut::new(r);
            pin_mut!(done);
            pin_mut!(pending);
            match futures::future::select(pending, done).await {
                Either::Right((5, _pending)) => (),
                _ => panic!("unexpected select result"),
            }
        }

        let fut = do_test();

        let mut ex = FdExecutor::new(crate::UnitFutures::new()).expect("Failed creating executor");
        add_future(Box::pin(fut)).unwrap();
        ex.run().unwrap();
        STATE.with(|state| {
            let state = state.borrow_mut();
            assert!(state.as_ref().unwrap().token_map.is_empty());
        });
    }

    #[test]
    fn run() {
        // Example of starting the framework and running a future:
        async fn my_async(x: Rc<RefCell<u64>>) {
            x.replace(4);
        }

        let mut ex = FdExecutor::new(crate::UnitFutures::new()).expect("Failed creating executor");
        let x = Rc::new(RefCell::new(0));
        crate::fd_executor::add_future(Box::pin(my_async(x.clone()))).unwrap();
        ex.run().unwrap();
        assert_eq!(*x.borrow(), 4);
    }
}
<commit_msg>cros_async: fd_executor: include UnitFutures for tests<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! The executor runs all given futures to completion. Futures register wakers associated with file
//! descriptors. The wakers will be called when the FD becomes readable or writable depending on
//! the situation.
//!
//! `FdExecutor` is meant to be used with the `futures-rs` crate that provides combinators and
//! utility functions to combine futures.

use std::cell::RefCell;
use std::collections::{BTreeMap, VecDeque};
use std::fmt::{self, Display};
use std::fs::File;
use std::future::Future;
use std::os::unix::io::FromRawFd;
use std::os::unix::io::RawFd;
use std::pin::Pin;
use std::task::Waker;

use sys_util::{PollContext, WatchingEvents};

use crate::executor::{ExecutableFuture, Executor, FutureList, WakerToken};

#[derive(Debug, PartialEq)]
pub enum Error {
    /// Attempts to create two Executors on the same thread fail.
    AttemptedDuplicateExecutor,
    /// Failed to copy the FD for the polling context.
    DuplicatingFd(sys_util::Error),
    /// Failed accessing the thread local storage for wakers.
    InvalidContext,
    /// Creating a context to wait on FDs failed.
    CreatingContext(sys_util::Error),
    /// PollContext failure.
    PollContextError(sys_util::Error),
    /// Failed to submit the waker to the polling context.
    SubmittingWaker(sys_util::Error),
}
pub type Result<T> = std::result::Result<T, Error>;

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            AttemptedDuplicateExecutor => write!(f, "Cannot have two executors on one thread."),
            DuplicatingFd(e) => write!(f, "Failed to copy the FD for the polling context: {}", e),
            InvalidContext => write!(
                f,
                "Invalid context, was the Fd executor created successfully?"
            ),
            CreatingContext(e) => write!(f, "An error creating the fd waiting context: {}.", e),
            PollContextError(e) => write!(f, "PollContext failure: {}", e),
            SubmittingWaker(e) => write!(f, "An error adding to the Aio context: {}.", e),
        }
    }
}

// Temporary vectors of new additions to the executor.

// Tracks active wakers and the futures they are associated with.
thread_local!(static STATE: RefCell<Option<FdWakerState>> = RefCell::new(None));

fn add_waker(fd: RawFd, waker: Waker, events: WatchingEvents) -> Result<WakerToken> {
    STATE.with(|state| {
        let mut state = state.borrow_mut();
        if let Some(state) = state.as_mut() {
            state.add_waker(fd, waker, events)
        } else {
            Err(Error::InvalidContext)
        }
    })
}

/// Tells the waking system to wake `waker` when `fd` becomes readable.
/// The 'fd' must be fully owned by the future adding the waker, and must not be closed until the
/// next time the future is polled. If the fd is closed, there is a race where another FD can be
/// opened on top of it causing the next poll to access the new target file.
/// Returns a `WakerToken` that can be used to cancel the waker before it completes.
pub fn add_read_waker(fd: RawFd, waker: Waker) -> Result<WakerToken> {
    add_waker(fd, waker, WatchingEvents::empty().set_read())
}

/// Tells the waking system to wake `waker` when `fd` becomes writable.
/// The 'fd' must be fully owned by the future adding the waker, and must not be closed until the
/// next time the future is polled. If the fd is closed, there is a race where another FD can be
/// opened on top of it causing the next poll to access the new target file.
/// Returns a `WakerToken` that can be used to cancel the waker before it completes.
pub fn add_write_waker(fd: RawFd, waker: Waker) -> Result<WakerToken> {
    add_waker(fd, waker, WatchingEvents::empty().set_write())
}

/// Cancels the waker that returned the given token if the waker hasn't yet fired.
pub fn cancel_waker(token: WakerToken) -> Result<()> {
    STATE.with(|state| {
        let mut state = state.borrow_mut();
        if let Some(state) = state.as_mut() {
            state.cancel_waker(token)
        } else {
            Err(Error::InvalidContext)
        }
    })
}

/// Adds a new top level future to the Executor.
/// These futures must return `()`, indicating they are intended to create side-effects only.
pub fn add_future(future: Pin<Box<dyn Future<Output = ()>>>) -> Result<()> {
    STATE.with(|state| {
        let mut state = state.borrow_mut();
        if let Some(state) = state.as_mut() {
            state.new_futures.push_back(ExecutableFuture::new(future));
            Ok(())
        } else {
            Err(Error::InvalidContext)
        }
    })
}

// Tracks active wakers and associates wakers with the futures that registered them.
struct FdWakerState {
    poll_ctx: PollContext<u64>,
    token_map: BTreeMap<u64, (File, Waker)>,
    next_token: u64, // Next token for adding to the context.
    new_futures: VecDeque<ExecutableFuture<()>>,
}

impl FdWakerState {
    fn new() -> Result<Self> {
        Ok(FdWakerState {
            poll_ctx: PollContext::new().map_err(Error::CreatingContext)?,
            token_map: BTreeMap::new(),
            next_token: 0,
            new_futures: VecDeque::new(),
        })
    }

    // Adds an fd that, when signaled, will trigger the given waker.
    fn add_waker(&mut self, fd: RawFd, waker: Waker, events: WatchingEvents) -> Result<WakerToken> {
        let duped_fd = unsafe {
            // Safe because duplicating an FD doesn't affect memory safety, and the dup'd FD
            // will only be added to the poll loop.
            File::from_raw_fd(dup_fd(fd)?)
        };
        self.poll_ctx
            .add_fd_with_events(&duped_fd, events, self.next_token)
            .map_err(Error::SubmittingWaker)?;
        let next_token = self.next_token;
        self.token_map.insert(next_token, (duped_fd, waker));
        self.next_token += 1;
        Ok(WakerToken(next_token))
    }

    // Waits until one of the FDs is readable and wakes the associated waker.
    fn wait_wake_event(&mut self) -> Result<()> {
        let events = self.poll_ctx.wait().map_err(Error::PollContextError)?;
        for e in events.iter() {
            if let Some((fd, waker)) = self.token_map.remove(&e.token()) {
                self.poll_ctx.delete(&fd).map_err(Error::PollContextError)?;
                waker.wake_by_ref();
            }
        }
        Ok(())
    }

    // Remove the waker for the given token if it hasn't fired yet.
    fn cancel_waker(&mut self, token: WakerToken) -> Result<()> {
        if let Some((fd, _waker)) = self.token_map.remove(&token.0) {
            self.poll_ctx.delete(&fd).map_err(Error::PollContextError)?;
        }
        Ok(())
    }
}

/// Runs futures to completion on a single thread. Futures are allowed to block on file descriptors
/// only. Futures can only block on FDs becoming readable or writable. `FdExecutor` is meant to be
/// used where a poll or select loop would be used otherwise.
pub(crate) struct FdExecutor<T: FutureList> {
    futures: T,
}

impl<T: FutureList> Executor for FdExecutor<T> {
    type Output = Result<T::Output>;

    fn run(&mut self) -> Self::Output {
        self.append_futures();

        loop {
            if let Some(output) = self.futures.poll_results() {
                return Ok(output);
            }

            self.append_futures();

            // If no futures are ready, sleep until a waker is signaled.
            if !self.futures.any_ready() {
                STATE.with(|state| {
                    let mut state = state.borrow_mut();
                    if let Some(state) = state.as_mut() {
                        state.wait_wake_event()?;
                    } else {
                        unreachable!("Can't get here without a context being created");
                    }
                    Ok(())
                })?;
            }
        }
    }
}

impl<T: FutureList> FdExecutor<T> {
    /// Create a new executor.
    pub fn new(futures: T) -> Result<FdExecutor<T>> {
        STATE.with(|state| {
            if state.borrow().is_some() {
                return Err(Error::AttemptedDuplicateExecutor);
            }
            state.replace(Some(FdWakerState::new()?));
            Ok(())
        })?;
        Ok(FdExecutor { futures })
    }

    // Add any new futures and wakers to the lists.
    fn append_futures(&mut self) {
        STATE.with(|state| {
            let mut state = state.borrow_mut();
            if let Some(state) = state.as_mut() {
                self.futures.futures_mut().append(&mut state.new_futures);
            } else {
                unreachable!("Can't get here without a context being created");
            }
        });
    }
}

impl<T: FutureList> Drop for FdExecutor<T> {
    fn drop(&mut self) {
        STATE.with(|state| {
            state.replace(None);
        });
    }
}

// Used to dup the FDs passed to the executor so there is a guarantee they aren't closed while
// waiting in TLS to be added to the main polling context.
unsafe fn dup_fd(fd: RawFd) -> Result<RawFd> {
    let ret = libc::dup(fd);
    if ret < 0 {
        Err(Error::DuplicatingFd(sys_util::Error::last()))
    } else {
        Ok(ret)
    }
}

#[cfg(test)]
mod test {
    use std::cell::RefCell;
    use std::future::Future;
    use std::os::unix::io::AsRawFd;
    use std::rc::Rc;
    use std::task::{Context, Poll};

    use futures::future::Either;
    use futures::pin_mut;

    use crate::executor::UnitFutures;

    use super::*;

    struct TestFut {
        f: File,
        token: Option<WakerToken>,
    }

    impl TestFut {
        fn new(f: File) -> TestFut {
            TestFut { f, token: None }
        }
    }

    impl Future for TestFut {
        type Output = u64;
        fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
            if self.token.is_none() {
                self.token = Some(add_read_waker(self.f.as_raw_fd(), cx.waker().clone()).unwrap());
            }
            Poll::Pending
        }
    }

    impl Drop for TestFut {
        fn drop(&mut self) {
            if let Some(token) = self.token.take() {
                cancel_waker(token).unwrap();
            }
        }
    }

    #[test]
    fn cancel() {
        async fn do_test() {
            let (r, _w) = sys_util::pipe(true).unwrap();
            let done = async { 5usize };
            let pending = TestFut::new(r);
            pin_mut!(done);
            pin_mut!(pending);
            match futures::future::select(pending, done).await {
                Either::Right((5, _pending)) => (),
                _ => panic!("unexpected select result"),
            }
        }

        let fut = do_test();

        let mut ex = FdExecutor::new(UnitFutures::new()).expect("Failed creating executor");
        add_future(Box::pin(fut)).unwrap();
        ex.run().unwrap();
        STATE.with(|state| {
            let state = state.borrow_mut();
            assert!(state.as_ref().unwrap().token_map.is_empty());
        });
    }

    #[test]
    fn run() {
        // Example of starting the framework and running a future:
        async fn my_async(x: Rc<RefCell<u64>>) {
            x.replace(4);
        }

        let mut ex = FdExecutor::new(UnitFutures::new()).expect("Failed creating executor");
        let x = Rc::new(RefCell::new(0));
        crate::fd_executor::add_future(Box::pin(my_async(x.clone()))).unwrap();
        ex.run().unwrap();
        assert_eq!(*x.borrow(), 4);
    }
}
<|endoftext|>


<commit_before>
// Std
use std::io::Write;

// Internal
use app::parser::Parser;
use INTERNAL_ERROR_MSG;

pub struct PowerShellGen<'a, 'b>
    where 'a: 'b
{
    p: &'b Parser<'a, 'b>,
}

impl<'a, 'b> PowerShellGen<'a, 'b> {
    pub fn new(p: &'b Parser<'a, 'b>) -> Self { PowerShellGen { p: p } }

    pub fn generate_to<W: Write>(&self, buf: &mut W) {
        let bin_name = self.p.meta.bin_name.as_ref().unwrap();

        let (subcommands_detection_cases, subcommands_cases) = generate_inner(self.p, "");

        let mut bin_names = vec![bin_name.to_string(), format!("./{0}", bin_name)];
        if cfg!(windows) {
            bin_names.push(format!("{0}.exe", bin_name));
            bin_names.push(format!(r".\{0}", bin_name));
            bin_names.push(format!(r".\{0}.exe", bin_name));
            bin_names.push(format!(r"./{0}.exe", bin_name));
        }

        let bin_names = bin_names.iter().fold(String::new(), |previous, current| {
            format!("{0}, '{1}'", previous, current)
        });
        let bin_names = bin_names.trim_left_matches(", ");

        let result = format!(r#"
@({bin_names}) | %{{
    Register-ArgumentCompleter -Native -CommandName $_ -ScriptBlock {{
        param($wordToComplete, $commandAst, $cursorPosition)

        $command = '_{bin_name}'
        $commandAst.CommandElements |
            Select-Object -Skip 1 |
            %{{
                switch ($_.ToString()) {{
{subcommands_detection_cases}
                    default {{
                        break
                    }}
                }}
            }}

        $completions = @()

        switch ($command) {{
{subcommands_cases}
        }}

        $completions |
            ?{{ $_ -like "$wordToComplete*" }} |
            Sort-Object |
            %{{ New-Object System.Management.Automation.CompletionResult $_, $_, 'ParameterValue', $_ }}
    }}
}}
"#,
            bin_names = bin_names,
            bin_name = bin_name,
            subcommands_detection_cases = subcommands_detection_cases,
            subcommands_cases = subcommands_cases
        );

        w!(buf, result.as_bytes());
    }
}

fn generate_inner<'a, 'b>(p: &Parser<'a, 'b>, previous_command_name: &str) -> (String, String) {
    debugln!("PowerShellGen::generate_inner;");
    let command_name = if previous_command_name.is_empty() {
        format!("{}_{}", previous_command_name, &p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG))
    } else {
        format!("{}_{}", previous_command_name, &p.meta.name)
    };

    let mut subcommands_detection_cases = if previous_command_name == "" {
        String::new()
    } else {
        format!(r"
                    '{0}' {{
                        $command += '_{0}'
                        break
                    }}
",
                &p.meta.name)
    };

    let mut completions = String::new();
    for subcommand in &p.subcommands {
        completions.push_str(&format!("'{}', ", &subcommand.p.meta.name));
    }
    for short in shorts!(p) {
        completions.push_str(&format!("'-{}', ", short));
    }
    for long in longs!(p) {
        completions.push_str(&format!("'--{}', ", long));
    }

    let mut subcommands_cases = format!(r"
            '{}' {{
                $completions = @({})
            }}
",
                                        &command_name,
                                        completions.trim_right_matches(", "));

    for subcommand in &p.subcommands {
        let (subcommand_subcommands_detection_cases, subcommand_subcommands_cases) =
            generate_inner(&subcommand.p, &command_name);
        subcommands_detection_cases.push_str(&subcommand_subcommands_detection_cases);
        subcommands_cases.push_str(&subcommand_subcommands_cases);
    }

    (subcommands_detection_cases, subcommands_cases)
}
<commit_msg>imp(PowerShell Completions): massively dedups subcommand names in the generate script to make smaller scripts that are still functionally equiv<commit_after>
// Std
use std::io::Write;

// Internal
use app::parser::Parser;
use INTERNAL_ERROR_MSG;

pub struct PowerShellGen<'a, 'b>
    where 'a: 'b
{
    p: &'b Parser<'a, 'b>,
}

impl<'a, 'b> PowerShellGen<'a, 'b> {
    pub fn new(p: &'b Parser<'a, 'b>) -> Self { PowerShellGen { p: p } }

    pub fn generate_to<W: Write>(&self, buf: &mut W) {
        let bin_name = self.p.meta.bin_name.as_ref().unwrap();

        let mut names = vec![];
        let (subcommands_detection_cases, subcommands_cases) = generate_inner(self.p, "", &mut names);

        let mut bin_names = vec![bin_name.to_string(), format!("./{0}", bin_name)];
        if cfg!(windows) {
            bin_names.push(format!("{0}.exe", bin_name));
            bin_names.push(format!(r".\{0}", bin_name));
            bin_names.push(format!(r".\{0}.exe", bin_name));
            bin_names.push(format!(r"./{0}.exe", bin_name));
        }

        let bin_names = bin_names.iter().fold(String::new(), |previous, current| {
            format!("{0}, '{1}'", previous, current)
        });
        let bin_names = bin_names.trim_left_matches(", ");

        let result = format!(r#"
@({bin_names}) | %{{
    Register-ArgumentCompleter -Native -CommandName $_ -ScriptBlock {{
        param($wordToComplete, $commandAst, $cursorPosition)

        $command = '_{bin_name}'
        $commandAst.CommandElements |
            Select-Object -Skip 1 |
            %{{
                switch ($_.ToString()) {{
{subcommands_detection_cases}
                    default {{
                        break
                    }}
                }}
            }}

        $completions = @()

        switch ($command) {{
{subcommands_cases}
        }}

        $completions |
            ?{{ $_ -like "$wordToComplete*" }} |
            Sort-Object |
            %{{ New-Object System.Management.Automation.CompletionResult $_, $_, 'ParameterValue', $_ }}
    }}
}}
"#,
            bin_names = bin_names,
            bin_name = bin_name,
            subcommands_detection_cases = subcommands_detection_cases,
            subcommands_cases = subcommands_cases
        );

        w!(buf, result.as_bytes());
    }
}

fn generate_inner<'a, 'b, 'p>(p: &'p Parser<'a, 'b>, previous_command_name: &str, names: &mut Vec<&'p str>) -> (String, String) {
    debugln!("PowerShellGen::generate_inner;");
    let command_name = if previous_command_name.is_empty() {
        format!("{}_{}", previous_command_name, &p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG))
    } else {
        format!("{}_{}", previous_command_name, &p.meta.name)
    };

    let mut subcommands_detection_cases = if previous_command_name.is_empty() {
        String::new()
    } else if !names.contains(&&*p.meta.name) {
        names.push(&&*p.meta.name);
        format!(r"
                    '{0}' {{
                        $command += '_{0}'
                        break
                    }}
",
                &p.meta.name)
    } else {
        String::new()
    };

    let mut completions = String::new();
    for subcommand in &p.subcommands {
        completions.push_str(&format!("'{}', ", &subcommand.p.meta.name));
    }
    for short in shorts!(p) {
        completions.push_str(&format!("'-{}', ", short));
    }
    for long in longs!(p) {
        completions.push_str(&format!("'--{}', ", long));
    }

    let mut subcommands_cases = format!(r"
            '{}' {{
                $completions = @({})
            }}
",
                                        &command_name,
                                        completions.trim_right_matches(", "));

    for subcommand in &p.subcommands {
        let (subcommand_subcommands_detection_cases, subcommand_subcommands_cases) =
            generate_inner(&subcommand.p, &command_name, names);
        subcommands_detection_cases.push_str(&subcommand_subcommands_detection_cases);
        subcommands_cases.push_str(&subcommand_subcommands_cases);
    }

    (subcommands_detection_cases, subcommands_cases)
}
<|endoftext|>


<commit_before>#[cfg(not(feature = "static-link"))]
mod imp {
    pub fn build() {
        #[cfg(feature = "snappy")]
        snappy();

        #[cfg(feature = "zlib")]
        zlib();

        #[cfg(feature = "bzip2")]
        bzip2();

        #[cfg(feature = "lz4")]
        lz4();

        #[cfg(feature = "zstd")]
        zstd();

        rocksdb();
    }

    #[cfg(feature = "snappy")]
    fn snappy() {
        let _ = pkg_config::Config::new().probe("snappy").map_err(|_| {
            println!("cargo:rustc-link-lib=dylib=snappy");
        });
    }

    #[cfg(feature = "zlib")]
    fn zlib() {
        let _ = pkg_config::Config::new().probe("zlib").map_err(|_| {
            println!("cargo:rustc-link-lib=dylib=z");
        });
    }

    #[cfg(feature = "bzip2")]
    fn bzip2() {
        println!("cargo:rustc-link-lib=dylib=bz2");
    }

    #[cfg(feature = "lz4")]
    fn lz4() {
        let _ = pkg_config::Config::new().probe("liblz4").map_err(|_| {
            println!("cargo:rustc-link-lib=dylib=lz4");
        });
    }

    #[cfg(feature = "zstd")]
    fn zstd() {
        let _ = pkg_config::Config::new().probe("libzstd").map_err(|_| {
            println!("cargo:rustc-link-lib=dylib=zstd");
        });
    }

    fn rocksdb() {
        println!("cargo:rustc-link-lib=rocksdb");
    }
}

#[cfg(feature = "static-link")]
mod imp {
    use std::env;
    use std::fs;
    use std::path::Path;
    use std::process::Command;

    pub fn build() {
        println!(
            "cargo:warning=static link feature enabled, it'll take minutes to finish compiling..."
        );

        #[cfg(feature = "snappy")]
        snappy();

        #[cfg(feature = "zlib")]
        zlib();

        #[cfg(feature = "bzip2")]
        bzip2();

        #[cfg(feature = "lz4")]
        lz4();

        #[cfg(feature = "zstd")]
        zstd();

        rocksdb();
    }

    #[cfg(feature = "snappy")]
    fn snappy() {
        if !Path::new("snappy/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "snappy"])
                .status();
        }

        // cmake can only have 1 run in 1 crate
        // or else the `build` directory will be overwritten
        let out_dir = env::var("OUT_DIR").unwrap();
        let this_out_dir = Path::new(&out_dir).join("snappy_out");
        let _ = fs::create_dir(&this_out_dir);

        let dst = cmake::Config::new("snappy")
            .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
            .build_target("snappy")
            .out_dir(this_out_dir)
            .very_verbose(true)
            .uses_cxx11()
            .build();

        println!("cargo:rustc-link-search=native={}/build/", dst.display());
        println!("cargo:rustc-link-lib=static=snappy");
    }

    #[cfg(feature = "zlib")]
    fn zlib() {
        if !Path::new("zlib/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "zlib"])
                .status();
        }

        Command::new(env::current_dir().unwrap().join("zlib/configure"))
            .current_dir(env::current_dir().unwrap().join("zlib"))
            .arg("--static")
            .output()
            .expect("failed to execute ./configure");

        let mut cfg = ::cc::Build::new();
        cfg.warnings(false);
        cfg.include("zlib");

        // TODO: borrow following list form Makefile
        let filez =
            "adler32.c crc32.c deflate.c infback.c inffast.c inflate.c inftrees.c trees.c zutil.c";
        let fileg = "compress.c uncompr.c gzclose.c gzlib.c gzread.c gzwrite.c";

        for file in filez.split(" ") {
            cfg.file(format!("zlib/{}", file));
        }
        for file in fileg.split(" ") {
            cfg.file(format!("zlib/{}", file));
        }

        cfg.pic(true);
        cfg.opt_level(2);
        cfg.compile("libz.a");
    }

    // Yes, copied from alexcrichton/bzip2-rs
    #[cfg(feature = "bzip2")]
    fn bzip2() {
        if !Path::new("bzip2/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "bzip2"])
                .status();
        }

        let mut cfg = ::cc::Build::new();

        if cfg!(windows) {
            cfg.define("_WIN32", None);
            cfg.define("BZ_EXPORT", None);
        }

        cfg.include("bzip2")
            .define("_FILE_OFFSET_BITS", Some("64"))
            .define("BZ_NO_STDIO", None)
            .opt_level(2)
            .warnings(false)
            .file("bzip2/blocksort.c")
            .file("bzip2/huffman.c")
            .file("bzip2/crctable.c")
            .file("bzip2/randtable.c")
            .file("bzip2/compress.c")
            .file("bzip2/decompress.c")
            .file("bzip2/bzlib.c")
            .compile("libbz2.a");
    }

    #[cfg(feature = "lz4")]
    fn lz4() {
        if !Path::new("lz4/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "lz4"])
                .status();
        }

        ::cc::Build::new()
            .warnings(false)
            .include("lz4/lib")
            .opt_level(2)
            .pic(true)
            .file("lz4/lib/lz4.c")
            .file("lz4/lib/lz4frame.c")
            .file("lz4/lib/lz4hc.c")
            .file("lz4/lib/xxhash.c")
            .compile("liblz4.a");
    }

    #[cfg(feature = "zstd")]
    fn zstd() {
        if !Path::new("zstd/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "zstd"])
                .status();
        }

        let files = [
            "zstd/lib/common/entropy_common.c",
            "zstd/lib/common/error_private.c",
            "zstd/lib/common/fse_decompress.c",
            "zstd/lib/common/pool.c",
            "zstd/lib/common/threading.c",
            "zstd/lib/common/xxhash.c",
            "zstd/lib/common/zstd_common.c",
            "zstd/lib/compress/fse_compress.c",
            "zstd/lib/compress/huf_compress.c",
            "zstd/lib/compress/zstd_compress.c",
            "zstd/lib/compress/zstdmt_compress.c",
            "zstd/lib/decompress/huf_decompress.c",
            "zstd/lib/decompress/zstd_decompress.c",
            "zstd/lib/dictBuilder/cover.c",
            "zstd/lib/dictBuilder/divsufsort.c",
            "zstd/lib/dictBuilder/zdict.c",
        ];

        ::cc::Build::new()
            .define("ZSTD_LEGACY_SUPPORT", Some("0"))
            .include("zstd/lib")
            .include("zstd/lib/common")
            .opt_level(3)
            .warnings(false)
            .files(&files)
            .compile("libzstd.a");
    }

    fn rocksdb() {
        if !Path::new("rocksdb/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "rocksdb"])
                .status();
        }

        let mut cfg = cmake::Config::new("rocksdb");

        #[cfg(feature = "snappy")]
        {
            let src = std::env::current_dir().unwrap();
            let out_dir = env::var("OUT_DIR").unwrap();
            let snappy_out_dir = Path::new(&out_dir).join("snappy_out");

            // FIXME: how to use cmake's define?
            cfg.cxxflag("-DSNAPPY");
            cfg.cxxflag(format!("-I{}", src.join("snappy").display()));
            // snappy-stubs-public.h
            cfg.cxxflag(format!("-I{}", snappy_out_dir.join("build").display()));
        }

        #[cfg(feature = "zlib")]
        {
            cfg.cxxflag("-DZLIB");
            cfg.cxxflag("-Izlib");
        }

        #[cfg(feature = "bzip2")]
        {
            cfg.cxxflag("-DBZIP2");
            cfg.cxxflag("-Ibzip2");
        }

        #[cfg(feature = "lz4")]
        {
            cfg.cxxflag("-DLZ4");
            cfg.cxxflag("-Ilz4/lib");
        }

        #[cfg(feature = "zstd")]
        {
            cfg.cxxflag("-DZSTD");
            cfg.cxxflag("-Izstd/lib");
        }

        cfg.build_target("rocksdb");
        let dst = cfg.build();

        println!("cargo:rustc-link-search=native={}/build/", dst.display());
        println!("cargo:rustc-link-lib=static=rocksdb");
    }
}

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=./");
    println!("cargo:rerun-if-changed=./rocks/");

    imp::build();

    let mut build = ::cc::Build::new();

    #[cfg(feature = "static-link")]
    {
        build.include("rocksdb/include");
    }

    build
        .cpp(true)
        .pic(true)
        .opt_level(2)
        .warnings(false)
        .flag("-std=c++11")
        .include(".")
        .file("rocks/cache.cc")
        .file("rocks/comparator.cc")
        .file("rocks/convenience.cc")
        .file("rocks/db.cc")
        .file("rocks/db_dump_tool.cc")
        .file("rocks/env.cc")
        .file("rocks/filter_policy.cc")
        .file("rocks/iostats_context.cc")
        .file("rocks/iterator.cc")
        .file("rocks/merge_operator.cc")
        .file("rocks/metadata.cc")
        .file("rocks/options.cc")
        .file("rocks/perf_context.cc")
        .file("rocks/perf_level.cc")
        .file("rocks/rate_limiter.cc")
        .file("rocks/slice.cc")
        .file("rocks/snapshot.cc")
        .file("rocks/sst_file_writer.cc")
        .file("rocks/statistics.cc")
        .file("rocks/status.cc")
        .file("rocks/table.cc")
        .file("rocks/table_properties.cc")
        .file("rocks/transaction_log.cc")
        .file("rocks/universal_compaction.cc")
        .file("rocks/util.cc")
        .file("rocks/write_batch.cc")
        .file("rocks/write_buffer_manager.cc")
        .file("rocks/debug.cc")
        .file("rocks/listener.cc")
        .file("rocks/compaction_job_stats.cc")
        .file("rocks/thread_status.cc")
        .compile("librocksdb_wrap.a");
}
<commit_msg>ci(rocks-sys): fix static build without gflags (#9)<commit_after>#[cfg(not(feature = "static-link"))]
mod imp {
    pub fn build() {
        #[cfg(feature = "snappy")]
        snappy();

        #[cfg(feature = "zlib")]
        zlib();

        #[cfg(feature = "bzip2")]
        bzip2();

        #[cfg(feature = "lz4")]
        lz4();

        #[cfg(feature = "zstd")]
        zstd();

        rocksdb();
    }

    #[cfg(feature = "snappy")]
    fn snappy() {
        let _ = pkg_config::Config::new().probe("snappy").map_err(|_| {
            println!("cargo:rustc-link-lib=dylib=snappy");
        });
    }

    #[cfg(feature = "zlib")]
    fn zlib() {
        let _ = pkg_config::Config::new().probe("zlib").map_err(|_| {
            println!("cargo:rustc-link-lib=dylib=z");
        });
    }

    #[cfg(feature = "bzip2")]
    fn bzip2() {
        println!("cargo:rustc-link-lib=dylib=bz2");
    }

    #[cfg(feature = "lz4")]
    fn lz4() {
        let _ = pkg_config::Config::new().probe("liblz4").map_err(|_| {
            println!("cargo:rustc-link-lib=dylib=lz4");
        });
    }

    #[cfg(feature = "zstd")]
    fn zstd() {
        let _ = pkg_config::Config::new().probe("libzstd").map_err(|_| {
            println!("cargo:rustc-link-lib=dylib=zstd");
        });
    }

    fn rocksdb() {
        println!("cargo:rustc-link-lib=rocksdb");
    }
}

#[cfg(feature = "static-link")]
mod imp {
    use std::env;
    use std::fs;
    use std::path::Path;
    use std::process::Command;

    pub fn build() {
        println!("cargo:warning=static link feature enabled, it'll take minutes to finish compiling...");

        #[cfg(feature = "snappy")]
        snappy();

        #[cfg(feature = "zlib")]
        zlib();

        #[cfg(feature = "bzip2")]
        bzip2();

        #[cfg(feature = "lz4")]
        lz4();

        #[cfg(feature = "zstd")]
        zstd();

        rocksdb();
    }

    #[cfg(feature = "snappy")]
    fn snappy() {
        if !Path::new("snappy/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "snappy"])
                .status();
        }

        // cmake can only have 1 run in 1 crate
        // or else the `build` directory will be overwritten
        let out_dir = env::var("OUT_DIR").unwrap();
        let this_out_dir = Path::new(&out_dir).join("snappy_out");
        let _ = fs::create_dir(&this_out_dir);

        let dst = cmake::Config::new("snappy")
            .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
            .build_target("snappy")
            .out_dir(this_out_dir)
            .very_verbose(true)
            .uses_cxx11()
            .build();

        println!("cargo:rustc-link-search=native={}/build/", dst.display());
        println!("cargo:rustc-link-lib=static=snappy");
    }

    #[cfg(feature = "zlib")]
    fn zlib() {
        if !Path::new("zlib/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "zlib"])
                .status();
        }

        Command::new(env::current_dir().unwrap().join("zlib/configure"))
            .current_dir(env::current_dir().unwrap().join("zlib"))
            .arg("--static")
            .output()
            .expect("failed to execute ./configure");

        let mut cfg = ::cc::Build::new();
        cfg.warnings(false);
        cfg.include("zlib");

        // TODO: borrow following list form Makefile
        let filez = "adler32.c crc32.c deflate.c infback.c inffast.c inflate.c inftrees.c trees.c zutil.c";
        let fileg = "compress.c uncompr.c gzclose.c gzlib.c gzread.c gzwrite.c";

        for file in filez.split(" ") {
            cfg.file(format!("zlib/{}", file));
        }
        for file in fileg.split(" ") {
            cfg.file(format!("zlib/{}", file));
        }

        cfg.pic(true);
        cfg.opt_level(2);
        cfg.compile("libz.a");
    }

    // Yes, copied from alexcrichton/bzip2-rs
    #[cfg(feature = "bzip2")]
    fn bzip2() {
        if !Path::new("bzip2/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "bzip2"])
                .status();
        }

        let mut cfg = ::cc::Build::new();

        if cfg!(windows) {
            cfg.define("_WIN32", None);
            cfg.define("BZ_EXPORT", None);
        }

        cfg.include("bzip2")
            .define("_FILE_OFFSET_BITS", Some("64"))
            .define("BZ_NO_STDIO", None)
            .opt_level(2)
            .warnings(false)
            .file("bzip2/blocksort.c")
            .file("bzip2/huffman.c")
            .file("bzip2/crctable.c")
            .file("bzip2/randtable.c")
            .file("bzip2/compress.c")
            .file("bzip2/decompress.c")
            .file("bzip2/bzlib.c")
            .compile("libbz2.a");
    }

    #[cfg(feature = "lz4")]
    fn lz4() {
        if !Path::new("lz4/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "lz4"])
                .status();
        }

        ::cc::Build::new()
            .warnings(false)
            .include("lz4/lib")
            .opt_level(2)
            .pic(true)
            .file("lz4/lib/lz4.c")
            .file("lz4/lib/lz4frame.c")
            .file("lz4/lib/lz4hc.c")
            .file("lz4/lib/xxhash.c")
            .compile("liblz4.a");
    }

    #[cfg(feature = "zstd")]
    fn zstd() {
        if !Path::new("zstd/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "zstd"])
                .status();
        }

        let files = [
            "zstd/lib/common/entropy_common.c",
            "zstd/lib/common/error_private.c",
            "zstd/lib/common/fse_decompress.c",
            "zstd/lib/common/pool.c",
            "zstd/lib/common/threading.c",
            "zstd/lib/common/xxhash.c",
            "zstd/lib/common/zstd_common.c",
            "zstd/lib/compress/fse_compress.c",
            "zstd/lib/compress/huf_compress.c",
            "zstd/lib/compress/zstd_compress.c",
            "zstd/lib/compress/zstdmt_compress.c",
            "zstd/lib/decompress/huf_decompress.c",
            "zstd/lib/decompress/zstd_decompress.c",
            "zstd/lib/dictBuilder/cover.c",
            "zstd/lib/dictBuilder/divsufsort.c",
            "zstd/lib/dictBuilder/zdict.c",
        ];

        ::cc::Build::new()
            .define("ZSTD_LEGACY_SUPPORT", Some("0"))
            .include("zstd/lib")
            .include("zstd/lib/common")
            .opt_level(3)
            .warnings(false)
            .files(&files)
            .compile("libzstd.a");
    }

    fn rocksdb() {
        if !Path::new("rocksdb/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "rocksdb"])
                .status();
        }

        let mut cfg = cmake::Config::new("rocksdb");

        #[cfg(feature = "snappy")]
        {
            let src = std::env::current_dir().unwrap();
            let out_dir = env::var("OUT_DIR").unwrap();
            let snappy_out_dir = Path::new(&out_dir).join("snappy_out");

            // FIXME: how to use cmake's define?
            cfg.cxxflag("-DSNAPPY");
            cfg.cxxflag(format!("-I{}", src.join("snappy").display()));
            // snappy-stubs-public.h
            cfg.cxxflag(format!("-I{}", snappy_out_dir.join("build").display()));
        }

        #[cfg(feature = "zlib")]
        {
            cfg.cxxflag("-DZLIB");
            cfg.cxxflag("-Izlib");
        }

        #[cfg(feature = "bzip2")]
        {
            cfg.cxxflag("-DBZIP2");
            cfg.cxxflag("-Ibzip2");
        }

        #[cfg(feature = "lz4")]
        {
            cfg.cxxflag("-DLZ4");
            cfg.cxxflag("-Ilz4/lib");
        }

        #[cfg(feature = "zstd")]
        {
            cfg.cxxflag("-DZSTD");
            cfg.cxxflag("-Izstd/lib");
        }

        let dst = cfg
            // .define("CMAKE_BUILD_TYPE", "Release") //  RelWithDebInfo
            .define("WITH_GFLAGS", "OFF")
            .build_target("rocksdb")
            .build();

        println!("cargo:rustc-link-search=native={}/build/", dst.display());
        println!("cargo:rustc-link-lib=static=rocksdb");
    }
}

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=./");
    println!("cargo:rerun-if-changed=./rocks/");

    imp::build();

    let mut build = ::cc::Build::new();

    #[cfg(feature = "static-link")]
    {
        build.include("rocksdb/include");
    }

    build
        .cpp(true)
        .pic(true)
        .opt_level(2)
        .warnings(false)
        .flag("-std=c++11")
        .include(".")
        .file("rocks/cache.cc")
        .file("rocks/comparator.cc")
        .file("rocks/convenience.cc")
        .file("rocks/db.cc")
        .file("rocks/db_dump_tool.cc")
        .file("rocks/env.cc")
        .file("rocks/filter_policy.cc")
        .file("rocks/iostats_context.cc")
        .file("rocks/iterator.cc")
        .file("rocks/merge_operator.cc")
        .file("rocks/metadata.cc")
        .file("rocks/options.cc")
        .file("rocks/perf_context.cc")
        .file("rocks/perf_level.cc")
        .file("rocks/rate_limiter.cc")
        .file("rocks/slice.cc")
        .file("rocks/snapshot.cc")
        .file("rocks/sst_file_writer.cc")
        .file("rocks/statistics.cc")
        .file("rocks/status.cc")
        .file("rocks/table.cc")
        .file("rocks/table_properties.cc")
        .file("rocks/transaction_log.cc")
        .file("rocks/universal_compaction.cc")
        .file("rocks/util.cc")
        .file("rocks/write_batch.cc")
        .file("rocks/write_buffer_manager.cc")
        .file("rocks/debug.cc")
        .file("rocks/listener.cc")
        .file("rocks/compaction_job_stats.cc")
        .file("rocks/thread_status.cc")
        .compile("librocksdb_wrap.a");
}
<|endoftext|>


<commit_before>extern crate rand;

use std::fmt;
use std::io;
use std::process::exit;
use std::time::{Instant, Duration};
use rand::{thread_rng, Rng};

/* basic objects */

#[derive(Debug, PartialEq, Clone, Copy)]
struct Coords {
	x: usize,
	y: usize
}

impl Coords {
	fn new(x: usize, y: usize) -> Coords {
		Coords {
			x: x,
			y: y
		}
	}

	fn new_io(c1: &str, c2: &str, max: usize) -> Result<Coords, GameError> {
		let x0 = c1.parse();
		let y0 = c2.parse();

		if x0.is_err() || y0.is_err() { return Err(GameError::InvalidCoords) };

		let x = x0.unwrap();
		let y = y0.unwrap();

		if x <= 0 || y <= 0 || x > max || y > max {
			Err(GameError::InvalidCoords)
		} else {
			Ok(Coords::new(x, y))
		}
	}

	fn neighbors(&self, max: usize) -> Vec<Coords> {
		let mut neighbors = Vec::with_capacity(8);
		let (x, y) = (self.x, self.y);

		neighbors.push(Coords::new(x, y-1));
		neighbors.push(Coords::new(x, y+1));
		neighbors.push(Coords::new(x-1, y));
		neighbors.push(Coords::new(x+1, y));
		neighbors.push(Coords::new(x-1, y-1));
		neighbors.push(Coords::new(x-1, y+1));
		neighbors.push(Coords::new(x+1, y-1));
		neighbors.push(Coords::new(x+1, y+1));

		neighbors.into_iter().filter(|n| n.x > 0 && n.y > 0 && n.x <= max && n.y <= max).collect()
	}
}

#[derive(Debug, PartialEq)]
struct Field {
	coords: Coords,
	is_rigged: bool,
	is_flagged: bool,
	is_visible: bool
}

impl Field {
	fn new(coords: Coords, is_rigged: bool) -> Field {
		Field {
			coords: coords,
			is_rigged: is_rigged,
			is_flagged: false,
			is_visible: false
		}
	}

	fn show(&mut self) {
		self.is_visible = true;
	}
}

#[derive(Debug)]
struct Grid {
	size: usize,
	fields: Vec<Field>
}

impl Grid {
	fn new(size: usize, density: u32) -> Grid {
		let mut fields = Vec::with_capacity(size);
		let mut is_rigged;
		let mut rng = thread_rng();

		for x in 1..(size + 1) {
			for y in 1..(size + 1) {
				is_rigged = rng.gen_weighted_bool(10 - density * 2);
				fields.push(Field::new(Coords::new(x, y), is_rigged));
			}
		}

		Grid {
			size: size,
			fields: fields
		}
	}

	fn field_at(&self, coords: Coords) -> &Field {
		self.fields.iter().find(|f| f.coords == coords).unwrap()
	}

	fn field_at_mut(&mut self, coords: Coords) -> &mut Field {
		self.fields.iter_mut().find(|f| f.coords == coords).unwrap()
	}

	fn mines_around(&self, coords: Coords) -> usize {
		let mut n = 0;

		for c in coords.neighbors(self.size) {
			if self.field_at(c).is_rigged { n += 1 }
		}

		n
	}
}

// a hack to bypass the trait coherence rules
struct Time(Duration);

/* visuals */

impl fmt::Display for Grid {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let limit = self.size + 1;
		let border_hor = '─';
		let border_ver = '│';
		let border_cross = '┼';

		// row line
		let mut row = String::new();
		row.push_str(&format!("{0}{0}{1}", border_hor, border_cross));
		for _ in 1..limit {
			row.push_str(&format!("{0}{0}{0}{1}", border_hor, border_cross));
		}
		row.push_str(&format!("{0}{0}", border_hor));

		// top numbers
		try!(write!(f, "  "));
		for n in 1..limit {
			try!(write!(f, "|{:^3}", n));
		}
		try!(writeln!(f, "|"));

		// fields
		for x in 1..limit {
			try!(writeln!(f, "{}", row));
			try!(write!(f, "{:2}", x));
			for y in 1..limit {
				let field = self.field_at(Coords::new(x, y));
				let disp = if field.is_flagged {
					"█".to_string()
				} else if !field.is_visible {
					"░".to_string()
				} else if field.is_rigged {
					"¤".to_string()
				} else {
					let n = self.mines_around(Coords::new(x, y));
					if n == 0 {
						" ".to_string()
					} else {
						format!("{}", n)
					}
				};
				try!(write!(f, "{} {} ", border_ver, disp));
			}
			try!(writeln!(f, "{}{:2}", border_ver, x));
		}
		try!(writeln!(f, "{}", row));

		// bottom numbers
		try!(write!(f, "  "));
		for n in 1..limit {
			try!(write!(f, "|{:^3}", n));
		}
		try!(writeln!(f, "|"));

		write!(f, "")
	}
}

impl fmt::Display for Time {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let mins = self.0.as_secs() / 60;
		let secs = self.0.as_secs() % 60;

		write!(f, "{}m{}s", mins, secs)
	}
}

/* the game */

struct Game {
	grid: Grid,
	uncovered: Vec<Coords>,
	buffer: String,
	time: Instant
}

enum GameAction {
	Resign,
	Uncover(Coords),
	Flag(Coords)
}

enum GameStatus {
	Proceed,
	GameOver,
	Victory
}

enum GameError {
	InvalidInput,
	InvalidCoords,
	FieldAlreadyVisible,
	FieldIsFlagged
}

impl Game {
	fn new(size: usize, difficulty: u32) -> Game {
		Game {
			grid: Grid::new(size, difficulty),
			uncovered: Vec::with_capacity(size^2),
			buffer: String::with_capacity(32),
			time: Instant::now()
		}
	}

	fn turn(&mut self) {
		println!("\n{}", self.grid);

		match self.check_status() {
			GameStatus::GameOver => {
				println!("wasted! time elapsed: {}", Time(self.time.elapsed()));
				exit(0)
			},
			GameStatus::Victory => {
				println!("victory! time elapsed: {}", Time(self.time.elapsed()));
				exit(0)
			},
			GameStatus::Proceed => ()
		}

		match self.handle_input() {
			Ok(a) => self.perform_action(a),
			Err(e) => self.print_error(e)
		}
	}

	fn check_status(&self) -> GameStatus {
		if let Some(_) = self.grid.fields.iter().find(|f| f.is_visible && f.is_rigged) {
			GameStatus::GameOver
		} else if self.uncovered.len() == self.grid.fields.iter().filter(|f| !f.is_rigged).collect::<Vec<_>>().len() {
			GameStatus::Victory
		} else {
			GameStatus::Proceed
		}
	}

	fn handle_input(&mut self) -> Result<GameAction, GameError> {
		self.buffer.clear();
		let _ = io::stdin().read_line(&mut self.buffer).unwrap();

		let words = self.buffer.split_whitespace().collect::<Vec<&str>>();
		if words.len() == 0 { return Err(GameError::InvalidInput) };

		if ["resign", "exit", "quit"].contains(&words[0]) {
			Ok(GameAction::Resign)
		} else {
			if words.len() != 3 { return Err(GameError::InvalidInput) };

			let coords = try!(Coords::new_io(&words[1], &words[2], self.grid.size));

			match words[0] {
				"uncover" | "u" => {
					if self.grid.field_at(coords).is_visible {
						Err(GameError::FieldAlreadyVisible)
					} else if self.grid.field_at(coords).is_flagged {
						Err(GameError::FieldIsFlagged)
					} else {
						Ok(GameAction::Uncover(coords))
					}
				},
				"flag" | "f" =>  {
					if self.grid.field_at(coords).is_visible {
						Err(GameError::FieldAlreadyVisible)
					} else {
						Ok(GameAction::Flag(coords))
					}
				},
				_ => Err(GameError::InvalidInput)
			}
		}
	}

	fn print_error(&self, error: GameError) {
		match error {
			GameError::InvalidCoords => println!("invalid coordinates!"),
			GameError::InvalidInput => println!("invalid command!"),
			GameError::FieldAlreadyVisible => println!("field already visible!"),
			GameError::FieldIsFlagged => println!("field is flagged!")
		}
	}

	fn perform_action(&mut self, action: GameAction) {
		match action {
			GameAction::Resign => { exit(0) },
			GameAction::Uncover(coords) => { self.uncover(coords) },
			GameAction::Flag(coords) => { self.flag(coords) }
		}
	}

	fn uncover(&mut self, coords: Coords) {
		self.grid.field_at_mut(coords).show();
		self.uncovered.push(coords);

		if !self.grid.field_at(coords).is_rigged && self.grid.mines_around(coords) == 0 {
			for c in coords.neighbors(self.grid.size) {
				if !self.grid.field_at(c).is_rigged && !self.uncovered.contains(&c) {
					self.uncover(c);
				}
			}
		}
	}

	fn flag(&mut self, coords: Coords) {
		if !self.grid.field_at(coords).is_visible {
			self.grid.field_at_mut(coords).is_flagged = !self.grid.field_at(coords).is_flagged;
		}
	}
}

/* game */

fn play() {
	let mut game = Game::new(10, 1);

	loop { game.turn() }
}

fn main() {
	play()
}

/* tests */

#[test]
fn neighbor_listing() {
	assert_eq!(Coords::new(1, 1).neighbors(2).len(), 3);
	assert_eq!(Coords::new(1, 2).neighbors(2).len(), 3);
	assert_eq!(Coords::new(2, 1).neighbors(2).len(), 3);
	assert_eq!(Coords::new(2, 2).neighbors(2).len(), 3);
}<commit_msg>fix the whitespaces, remove the superfluous test<commit_after>extern crate rand;

use std::fmt;
use std::io;
use std::process::exit;
use std::time::{Instant, Duration};
use rand::{thread_rng, Rng};

/* basic objects */

#[derive(Debug, PartialEq, Clone, Copy)]
struct Coords {
	x: usize,
	y: usize
}

impl Coords {
	fn new(x: usize, y: usize) -> Coords {
		Coords {
			x: x,
			y: y
		}
	}

	fn new_io(c1: &str, c2: &str, max: usize) -> Result<Coords, GameError> {
		let x0 = c1.parse();
		let y0 = c2.parse();

		if x0.is_err() || y0.is_err() { return Err(GameError::InvalidCoords) };

		let x = x0.unwrap();
		let y = y0.unwrap();

		if x <= 0 || y <= 0 || x > max || y > max {
			Err(GameError::InvalidCoords)
		} else {
			Ok(Coords::new(x, y))
		}
	}

	fn neighbors(&self, max: usize) -> Vec<Coords> {
		let mut neighbors = Vec::with_capacity(8);
		let (x, y) = (self.x, self.y);

		neighbors.push(Coords::new(x, y-1));
		neighbors.push(Coords::new(x, y+1));
		neighbors.push(Coords::new(x-1, y));
		neighbors.push(Coords::new(x+1, y));
		neighbors.push(Coords::new(x-1, y-1));
		neighbors.push(Coords::new(x-1, y+1));
		neighbors.push(Coords::new(x+1, y-1));
		neighbors.push(Coords::new(x+1, y+1));

		neighbors.into_iter().filter(|n| n.x > 0 && n.y > 0 && n.x <= max && n.y <= max).collect()
	}
}

#[derive(Debug, PartialEq)]
struct Field {
	coords: Coords,
	is_rigged: bool,
	is_flagged: bool,
	is_visible: bool
}

impl Field {
	fn new(coords: Coords, is_rigged: bool) -> Field {
		Field {
			coords: coords,
			is_rigged: is_rigged,
			is_flagged: false,
			is_visible: false
		}
	}

	fn show(&mut self) {
		self.is_visible = true;
	}
}

#[derive(Debug)]
struct Grid {
	size: usize,
	fields: Vec<Field>
}

impl Grid {
	fn new(size: usize, density: u32) -> Grid {
		let mut fields = Vec::with_capacity(size);
		let mut is_rigged;
		let mut rng = thread_rng();

		for x in 1..(size + 1) {
			for y in 1..(size + 1) {
				is_rigged = rng.gen_weighted_bool(10 - density * 2);
				fields.push(Field::new(Coords::new(x, y), is_rigged));
			}
		}

		Grid {
			size: size,
			fields: fields
		}
	}

	fn field_at(&self, coords: Coords) -> &Field {
		self.fields.iter().find(|f| f.coords == coords).unwrap()
	}

	fn field_at_mut(&mut self, coords: Coords) -> &mut Field {
		self.fields.iter_mut().find(|f| f.coords == coords).unwrap()
	}

	fn mines_around(&self, coords: Coords) -> usize {
		let mut n = 0;

		for c in coords.neighbors(self.size) {
			if self.field_at(c).is_rigged { n += 1 }
		}

		n
	}
}

// a hack to bypass the trait coherence rules
struct Time(Duration);

/* visuals */

impl fmt::Display for Grid {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let limit = self.size + 1;
		let border_hor = '─';
		let border_ver = '│';
		let border_cross = '┼';

		// row line
		let mut row = String::new();
		row.push_str(&format!("{0}{0}{1}", border_hor, border_cross));
		for _ in 1..limit {
			row.push_str(&format!("{0}{0}{0}{1}", border_hor, border_cross));
		}
		row.push_str(&format!("{0}{0}", border_hor));

		// top numbers
		try!(write!(f, "  "));
		for n in 1..limit {
			try!(write!(f, "|{:^3}", n));
		}
		try!(writeln!(f, "|"));

		// fields
		for x in 1..limit {
			try!(writeln!(f, "{}", row));
			try!(write!(f, "{:2}", x));
			for y in 1..limit {
				let field = self.field_at(Coords::new(x, y));
				let disp = if field.is_flagged {
					"█".to_string()
				} else if !field.is_visible {
					"░".to_string()
				} else if field.is_rigged {
					"¤".to_string()
				} else {
					let n = self.mines_around(Coords::new(x, y));
					if n == 0 {
						" ".to_string()
					} else {
						format!("{}", n)
					}
				};
				try!(write!(f, "{} {} ", border_ver, disp));
			}
			try!(writeln!(f, "{}{:2}", border_ver, x));
		}
		try!(writeln!(f, "{}", row));

		// bottom numbers
		try!(write!(f, "  "));
		for n in 1..limit {
			try!(write!(f, "|{:^3}", n));
		}
		try!(writeln!(f, "|"));

		write!(f, "")
	}
}

impl fmt::Display for Time {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let mins = self.0.as_secs() / 60;
		let secs = self.0.as_secs() % 60;

		write!(f, "{}m{}s", mins, secs)
	}
}

/* the game */

struct Game {
	grid: Grid,
	uncovered: Vec<Coords>,
	buffer: String,
	time: Instant
}

enum GameAction {
	Resign,
	Uncover(Coords),
	Flag(Coords)
}

enum GameStatus {
	Proceed,
	GameOver,
	Victory
}

enum GameError {
	InvalidInput,
	InvalidCoords,
	FieldAlreadyVisible,
	FieldIsFlagged
}

impl Game {
	fn new(size: usize, difficulty: u32) -> Game {
		Game {
			grid: Grid::new(size, difficulty),
			uncovered: Vec::with_capacity(size^2),
			buffer: String::with_capacity(32),
			time: Instant::now()
		}
	}

	fn turn(&mut self) {
		println!("\n{}", self.grid);

		match self.check_status() {
			GameStatus::GameOver => {
				println!("wasted! time elapsed: {}", Time(self.time.elapsed()));
				exit(0)
			},
			GameStatus::Victory => {
				println!("victory! time elapsed: {}", Time(self.time.elapsed()));
				exit(0)
			},
			GameStatus::Proceed => ()
		}

		match self.handle_input() {
			Ok(a) => self.perform_action(a),
			Err(e) => self.print_error(e)
		}
	}

	fn check_status(&self) -> GameStatus {
		if let Some(_) = self.grid.fields.iter().find(|f| f.is_visible && f.is_rigged) {
			GameStatus::GameOver
		} else if self.uncovered.len() == self.grid.fields.iter().filter(|f| !f.is_rigged).collect::<Vec<_>>().len() {
			GameStatus::Victory
		} else {
			GameStatus::Proceed
		}
	}

	fn handle_input(&mut self) -> Result<GameAction, GameError> {
		self.buffer.clear();
		let _ = io::stdin().read_line(&mut self.buffer).unwrap();

		let words = self.buffer.split_whitespace().collect::<Vec<&str>>();
		if words.len() == 0 { return Err(GameError::InvalidInput) };

		if ["resign", "exit", "quit"].contains(&words[0]) {
			Ok(GameAction::Resign)
		} else {
			if words.len() != 3 { return Err(GameError::InvalidInput) };

			let coords = try!(Coords::new_io(&words[1], &words[2], self.grid.size));

			match words[0] {
				"uncover" | "u" => {
					if self.grid.field_at(coords).is_visible {
						Err(GameError::FieldAlreadyVisible)
					} else if self.grid.field_at(coords).is_flagged {
						Err(GameError::FieldIsFlagged)
					} else {
						Ok(GameAction::Uncover(coords))
					}
				},
				"flag" | "f" =>  {
					if self.grid.field_at(coords).is_visible {
						Err(GameError::FieldAlreadyVisible)
					} else {
						Ok(GameAction::Flag(coords))
					}
				},
				_ => Err(GameError::InvalidInput)
			}
		}
	}

	fn print_error(&self, error: GameError) {
		match error {
			GameError::InvalidCoords => println!("invalid coordinates!"),
			GameError::InvalidInput => println!("invalid command!"),
			GameError::FieldAlreadyVisible => println!("field already visible!"),
			GameError::FieldIsFlagged => println!("field is flagged!")
		}
	}

	fn perform_action(&mut self, action: GameAction) {
		match action {
			GameAction::Resign => { exit(0) },
			GameAction::Uncover(coords) => { self.uncover(coords) },
			GameAction::Flag(coords) => { self.flag(coords) }
		}
	}

	fn uncover(&mut self, coords: Coords) {
		self.grid.field_at_mut(coords).show();
		self.uncovered.push(coords);

		if !self.grid.field_at(coords).is_rigged && self.grid.mines_around(coords) == 0 {
			for c in coords.neighbors(self.grid.size) {
				if !self.grid.field_at(c).is_rigged && !self.uncovered.contains(&c) {
					self.uncover(c);
				}
			}
		}
	}

	fn flag(&mut self, coords: Coords) {
		if !self.grid.field_at(coords).is_visible {
			self.grid.field_at_mut(coords).is_flagged = !self.grid.field_at(coords).is_flagged;
		}
	}
}

/* game */

fn play() {
	let mut game = Game::new(10, 1);

	loop { game.turn() }
}

fn main() {
	play()
}
<|endoftext|>


<commit_before>#[cfg(feature="logger")]
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate futures;
extern crate tokio_core;
extern crate tokio_timer;
extern crate recon_link;

use std::io;
use std::time::Duration;
use futures::{Async, AsyncSink, Poll, StartSend};
use futures::future::Future;
use futures::stream::{self, Stream};
use futures::sink::{Sink};
use tokio_core::reactor::Core;
use tokio_timer::Timer;
use recon_link::conn::{Connection, Message};

fn init_logger() {
    if cfg!(feature="logger") {
        env_logger::init().unwrap();
    }
}

fn main() {
    init_logger();

    info!("hello, world!");

    let timer = Timer::default();
    let mut core = Core::new().unwrap();

    let addr = "127.0.0.1:6666".parse().unwrap();

    let stream = stream::iter_ok((1..1000).map(|n| format!("{}\n", n)))
        .and_then(|value| {
            debug!("next value is {}", value);
            timer.sleep(Duration::from_millis(500))
                .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
                .map(|_| {
                    debug!("producing delayed value {}", value);
                    value
                })
        });

    let conn = Connection::new(addr, core.handle(), stream, PrinterSink);

    core.run(conn).unwrap();
}

struct PrinterSink;

impl Sink for PrinterSink {
    type SinkItem = Message;
    type SinkError = io::Error;

    fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
        let s = String::from_utf8_lossy(&item.content[..]);
        println!("{}", s);
        Ok(AsyncSink::Ready)
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        Ok(Async::Ready(()))
    }
}<commit_msg>make example compile without features<commit_after>#[cfg(feature="logger")]
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate futures;
extern crate tokio_core;
extern crate tokio_timer;
extern crate recon_link;

use std::io;
use std::time::Duration;
use futures::{Async, AsyncSink, Poll, StartSend};
use futures::future::Future;
use futures::stream::{self, Stream};
use futures::sink::{Sink};
use tokio_core::reactor::Core;
use tokio_timer::Timer;
use recon_link::conn::{Connection, Message};

#[cfg(feature="logger")]
mod logging {
    pub fn init_logger() {
        env_logger::init().unwrap();
    }
}

#[cfg(not(feature="logger"))]
mod logging {
    pub fn init_logger() {}
}

fn main() {
    logging::init_logger();

    info!("hello, world!");

    let timer = Timer::default();
    let mut core = Core::new().unwrap();

    let addr = "127.0.0.1:6666".parse().unwrap();

    let stream = stream::iter_ok((1..1000).map(|n| format!("{}\n", n)))
        .and_then(|value| {
            debug!("next value is {}", value);
            timer.sleep(Duration::from_millis(500))
                .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
                .map(|_| {
                    debug!("producing delayed value {}", value);
                    value
                })
        });

    let conn = Connection::new(addr, core.handle(), stream, PrinterSink);

    core.run(conn).unwrap();
}

struct PrinterSink;

impl Sink for PrinterSink {
    type SinkItem = Message;
    type SinkError = io::Error;

    fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
        let s = String::from_utf8_lossy(&item.content[..]);
        println!("{}", s);
        Ok(AsyncSink::Ready)
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        Ok(Async::Ready(()))
    }
}<|endoftext|>


<commit_before>extern crate libc;
extern crate scanifc_sys;

use std::ffi::{IntoStringError, NulError};

const LAST_ERROR_BUFFER_SIZE: usize = 256;

macro_rules! scanifc_try {
    ($expr:expr) => ({
        let result = unsafe { $expr };
        if result != 0 {
            let msg = last_error()?;
            return Err(Error::Scanifc(result, msg));
        }
    })
}

/// Our custom error enum.
#[derive(Debug)]
pub enum Error {
    /// An error occurred while getting the last error.
    ///
    /// At this point, all we can do is return the error code from get_last_error.
    GetLastError(libc::c_int),
    /// Wrapper around `std::ffi::IntoStringError`.
    FfiIntoString(IntoStringError),
    /// Wrapper around `std::ffi::NulError`.
    FfiNulError(NulError),
    /// The last error message can't be turned into a string nicely.
    LastErrorMessage(Vec<libc::c_char>),
    /// A internal scanifc error.
    ///
    /// The message is provided by the scanifc library.
    Scanifc(libc::c_int, String),
}

/// Our custom result type.
pub type Result<T> = std::result::Result<T, Error>;

/// The version of the scanifc library.
#[derive(Clone, Copy, Debug, Default)]
pub struct Version {
    /// The major version number.
    pub major: u16,
    /// The minor version number.
    pub minor: u16,
    /// The build version.
    pub build: u16,
}

/// Returns the version number from the library.
///
/// # Examples
///
/// ```
/// let version = scanifc::library_version().unwrap();
/// println!("Version: {}.{}.{}", version.major, version.minor, version.build);
/// ```
pub fn library_version() -> Result<Version> {
    let mut version = Version::default();
    scanifc_try!(scanifc_sys::scanifc_get_library_version(
        &mut version.major,
        &mut version.minor,
        &mut version.build,
    ));
    Ok(version)
}

/// Returns the last error message recorded by the scanifc library.
///
/// # Examples
///
/// ```
/// let message = scanifc::last_error().unwrap();
/// ```
pub fn last_error() -> Result<String> {
    use std::ffi::CString;

    let mut buffer = vec![0; LAST_ERROR_BUFFER_SIZE];
    let mut message_size = 0;
    let result = unsafe {
        scanifc_sys::scanifc_get_last_error(
            buffer.as_mut_ptr(),
            buffer.len() as u32,
            &mut message_size,
        )
    };
    if result != 0 {
        return Err(Error::GetLastError(result));
    }
    let c_string = CString::new(buffer
        .iter()
        .take(message_size as usize)
        .map(|&n| if n < 0 {
            Err(Error::LastErrorMessage(buffer.clone()))
        } else {
            Ok(n as u8)
        })
        .collect::<Result<Vec<u8>>>()?)?;
    c_string.into_string().map_err(Error::from)
}

impl From<IntoStringError> for Error {
    fn from(err: IntoStringError) -> Error {
        Error::FfiIntoString(err)
    }
}

impl From<NulError> for Error {
    fn from(err: NulError) -> Error {
        Error::FfiNulError(err)
    }
}

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

    #[test]
    fn library_version_is_ok() {
        assert!(library_version().is_ok());
    }
}
<commit_msg>Add library info<commit_after>extern crate libc;
extern crate scanifc_sys;

use std::ffi::{IntoStringError, NulError};

const LAST_ERROR_BUFFER_SIZE: usize = 256;

macro_rules! scanifc_try {
    ($expr:expr) => ({
        let result = unsafe { $expr };
        if result != 0 {
            let msg = last_error()?;
            return Err(Error::Scanifc(result, msg));
        }
    })
}

/// Our custom error enum.
#[derive(Debug)]
pub enum Error {
    /// An error occurred while getting the last error.
    ///
    /// At this point, all we can do is return the error code from get_last_error.
    GetLastError(libc::c_int),
    /// Wrapper around `std::ffi::IntoStringError`.
    FfiIntoString(IntoStringError),
    /// Wrapper around `std::ffi::NulError`.
    FfiNulError(NulError),
    /// The last error message can't be turned into a string nicely.
    LastErrorMessage(Vec<libc::c_char>),
    /// A internal scanifc error.
    ///
    /// The message is provided by the scanifc library.
    Scanifc(libc::c_int, String),
}

/// Our custom result type.
pub type Result<T> = std::result::Result<T, Error>;

/// The version of the scanifc library.
#[derive(Clone, Copy, Debug, Default)]
pub struct Version {
    /// The major version number.
    pub major: u16,
    /// The minor version number.
    pub minor: u16,
    /// The build version.
    pub build: u16,
}

/// Returns the version number from the library.
///
/// # Examples
///
/// ```
/// let version = scanifc::library_version().unwrap();
/// println!("Version: {}.{}.{}", version.major, version.minor, version.build);
/// ```
pub fn library_version() -> Result<Version> {
    let mut version = Version::default();
    scanifc_try!(scanifc_sys::scanifc_get_library_version(
        &mut version.major,
        &mut version.minor,
        &mut version.build,
    ));
    Ok(version)
}

/// Returns extended version information that allows traceability of the SCM system.
///
/// # Examples
///
/// ```
/// let version = scanifc::library_build_version();
/// ```
pub fn library_build_version() -> Result<String> {
    library_info().map(|(version, _)| version)
}

/// Returns additional information about the build.
///
/// # Examples
///
/// ```
/// let tag = scanifc::library_build_tag();
/// ```
pub fn library_build_tag() -> Result<String> {
    library_info().map(|(_, tag)| tag)
}

/// Returns the last error message recorded by the scanifc library.
///
/// # Examples
///
/// ```
/// let message = scanifc::last_error().unwrap();
/// ```
pub fn last_error() -> Result<String> {
    use std::ffi::CString;

    let mut buffer = vec![0; LAST_ERROR_BUFFER_SIZE];
    let mut message_size = 0;
    let result = unsafe {
        scanifc_sys::scanifc_get_last_error(
            buffer.as_mut_ptr(),
            buffer.len() as u32,
            &mut message_size,
        )
    };
    if result != 0 {
        return Err(Error::GetLastError(result));
    }
    let c_string = CString::new(buffer
        .iter()
        .take(message_size as usize)
        .map(|&n| if n < 0 {
            Err(Error::LastErrorMessage(buffer.clone()))
        } else {
            Ok(n as u8)
        })
        .collect::<Result<Vec<u8>>>()?)?;
    c_string.into_string().map_err(Error::from)
}

impl From<IntoStringError> for Error {
    fn from(err: IntoStringError) -> Error {
        Error::FfiIntoString(err)
    }
}

impl From<NulError> for Error {
    fn from(err: NulError) -> Error {
        Error::FfiNulError(err)
    }
}

fn library_info() -> Result<(String, String)> {
    use std::ptr;
    use std::ffi::CStr;

    let mut version: *const libc::c_char = ptr::null();
    let mut tag: *const libc::c_char = ptr::null();
    scanifc_try!(scanifc_sys::scanifc_get_library_info(
        &mut version,
        &mut tag,
    ));
    let version = unsafe { CStr::from_ptr(version) };
    let tag = unsafe { CStr::from_ptr(tag) };
    Ok((
        version.to_string_lossy().into_owned(),
        tag.to_string_lossy().into_owned(),
    ))
}

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

    #[test]
    fn library_version_is_ok() {
        assert!(library_version().is_ok());
    }

    #[test]
    fn library_build_version_is_ok() {
        assert!(library_build_version().is_ok());
    }

    #[test]
    fn library_build_tag_is_ok() {
        assert!(library_build_tag().is_ok());
    }
}
<|endoftext|>


<commit_before>use ptr::{null, addr_of};
use result::{Result, Ok, Err};
use libc::{c_char, c_uint};
use name_pool::{name_pool, add};
use str::raw::from_c_str;
use io::WriterUtil;
use jsapi::{JSBool, JSClass, JSContext, JSErrorReport, JSFunctionSpec,
               JSObject, JSRuntime, JSString, JSVERSION_LATEST, jsval,
               JSPropertySpec, JSPropertyOp, JSStrictPropertyOp};
use jsapi::bindgen::{JS_free, JS_AddObjectRoot, JS_DefineFunctions,
                        JS_DestroyContext, JS_EncodeString, JS_EvaluateScript,
                        JS_Finish, JS_GetContextPrivate, JS_GetPrivate,
                        JS_Init, JS_InitStandardClasses,
                        JS_NewGlobalObject, JS_NewContext,
                        JS_RemoveObjectRoot, JS_SetContextPrivate,
                        JS_SetErrorReporter, JS_SetOptions, JS_SetPrivate,
                        JS_SetVersion, JS_ValueToString, JS_DefineProperties,
                        JS_DefineProperty, JS_NewObject, JS_ComputeThis};
use libc::types::common::c99::{int8_t, int16_t, int32_t, int64_t, uint8_t,
                                  uint16_t, uint32_t, uint64_t};
use glue::bindgen::{RUST_JSVAL_TO_OBJECT, RUST_JSVAL_IS_PRIMITIVE};
use rust::jsobj;

export JSOPTION_STRICT;
export JSOPTION_WERROR;
export JSOPTION_VAROBJFIX;
export JSOPTION_METHODJIT;

export JSPROP_ENUMERATE;
export JSPROP_SHARED;
export JSPROP_NATIVE_ACCESSORS;

export JSCLASS_GLOBAL_FLAGS;
export JSCLASS_HAS_RESERVED_SLOTS;

export rust;
export name_pool;

export jsapi;
export global;
export glue;
export crust;

export ptr_methods;

// These are just macros in jsapi.h
use JS_NewRuntime = jsapi::bindgen::JS_Init;
export JS_NewRuntime;
use JS_DestroyRuntime = jsapi::bindgen::JS_Finish;
export JS_DestroyRuntime;
/*
FIXME: Not sure where JS_Lock is
use JS_LockRuntime = jsapi::bindgen::JS_Lock;
export JS_LockRuntime;
use JS_UnlockRuntime = jsapi::bindgen::JS_Unlock;
export JS_UnlockRuntime;
*/

export JS_ARGV;
export JS_SET_RVAL;
export JS_THIS_OBJECT;
export JSVAL_VOID;
export JSVAL_NULL;
export JSVAL_ZERO;
export JSVAL_ONE;
export JSVAL_FALSE;
export JSVAL_TRUE;

// FIXME: Add the remaining options
const JSOPTION_STRICT: uint32_t =    0b00000000000001u32;
const JSOPTION_WERROR: uint32_t =    0b00000000000010u32;
const JSOPTION_VAROBJFIX: uint32_t = 0b00000000000100u32;
//const JSOPTION_METHODJIT: uint32_t = 0b100000000000000u32;
const JSOPTION_METHODJIT: uint32_t = (1 << 14) as u32;

const default_heapsize: u32 = 8_u32 * 1024_u32 * 1024_u32;
const default_stacksize: uint = 8192u;
const ERR: JSBool = 0_i32;

const JSVAL_TAG_MAX_DOUBLE: u64 = 0x1FFF0;

const JSVAL_TYPE_DOUBLE: u64 = 0x00;
const JSVAL_TYPE_INT32: u64 = 0x01;
const JSVAL_TYPE_UNDEFINED: u64 = 0x02;
const JSVAL_TYPE_BOOLEAN: u64 = 0x03;
const JSVAL_TYPE_MAGIC: u64 = 0x04;
const JSVAL_TYPE_STRING: u64 = 0x05;
const JSVAL_TYPE_NULL: u64 = 0x06;
const JSVAL_TYPE_OBJECT: u64 = 0x07;
const JSVAL_TYPE_UNKNOWN: u64 = 0x20;

const JSVAL_TAG_SHIFT: int = 47;

//The following constants are totally broken on non-64bit platforms.
//See jsapi.h for the proper macro definitions.
const JSVAL_VOID: u64 = (JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNKNOWN) << JSVAL_TAG_SHIFT;
const JSVAL_NULL: u64 = (JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL) << JSVAL_TAG_SHIFT;
const JSVAL_ZERO: u64 = (JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32) << JSVAL_TAG_SHIFT;
const JSVAL_ONE: u64 = ((JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32) << JSVAL_TAG_SHIFT) | 1;
const JSVAL_FALSE: u64 = (JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN) << JSVAL_TAG_SHIFT;
const JSVAL_TRUE: u64 = ((JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN) << JSVAL_TAG_SHIFT) | 1;

const JSPROP_ENUMERATE: c_uint = 0x01;
const JSPROP_READONLY: c_uint  = 0x02;
const JSPROP_SHARED: c_uint =    0x40;
const JSPROP_NATIVE_ACCESSORS: c_uint = 0x08;

const JSCLASS_RESERVED_SLOTS_SHIFT: c_uint = 8;
const JSCLASS_RESERVED_SLOTS_WIDTH: c_uint = 8;
const JSCLASS_RESERVED_SLOTS_MASK: c_uint = ((1 << JSCLASS_RESERVED_SLOTS_WIDTH) - 1);

const JSCLASS_HIGH_FLAGS_SHIFT: c_uint =
    JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH;
const JSCLASS_IS_GLOBAL: c_uint = (1<<(JSCLASS_HIGH_FLAGS_SHIFT+1));

const JSCLASS_GLOBAL_SLOT_COUNT: c_uint = JSProto_LIMIT * 3 + 24;

pure fn JSCLASS_HAS_RESERVED_SLOTS(n: c_uint) -> c_uint {
    (n & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT
}

fn result(n: JSBool) -> Result<(),()> {
    if n != ERR {Ok(())} else {Err(())}
}
fn result_obj(o: jsobj) -> Result<jsobj, ()> {
    if o.ptr != null() {Ok(o)} else {Err(())}
}

type named_functions = @{
    names: ~[~str],
    funcs: ~[JSFunctionSpec]
};

#[inline(always)]
unsafe fn JS_ARGV(_cx: *JSContext, vp: *jsval) -> *jsval {
    ptr::offset(vp, 2u)
}

unsafe fn JS_SET_RVAL(_cx: *JSContext, vp: *jsval, v: jsval) {
    let vp: *mut jsval = cast::reinterpret_cast(&vp);
    *vp = v;
}

#[inline(always)]
unsafe fn JS_THIS_OBJECT(cx: *JSContext, vp: *jsval) -> *JSObject unsafe {
    let r = RUST_JSVAL_TO_OBJECT(
        if RUST_JSVAL_IS_PRIMITIVE(*ptr::offset(vp, 1)) == 0 {
            JS_ComputeThis(cx, vp)
        } else {
            *ptr::offset(vp, 1)
        });
    r
}

<commit_msg>Fix missing import<commit_after>use ptr::{null, addr_of};
use result::{Result, Ok, Err};
use libc::{c_char, c_uint};
use name_pool::{name_pool, add};
use str::raw::from_c_str;
use io::WriterUtil;
use jsapi::{JSBool, JSClass, JSContext, JSErrorReport, JSFunctionSpec,
               JSObject, JSRuntime, JSString, JSVERSION_LATEST, jsval,
               JSPropertySpec, JSPropertyOp, JSStrictPropertyOp, JSProto_LIMIT};
use jsapi::bindgen::{JS_free, JS_AddObjectRoot, JS_DefineFunctions,
                        JS_DestroyContext, JS_EncodeString, JS_EvaluateScript,
                        JS_Finish, JS_GetContextPrivate, JS_GetPrivate,
                        JS_Init, JS_InitStandardClasses,
                        JS_NewGlobalObject, JS_NewContext,
                        JS_RemoveObjectRoot, JS_SetContextPrivate,
                        JS_SetErrorReporter, JS_SetOptions, JS_SetPrivate,
                        JS_SetVersion, JS_ValueToString, JS_DefineProperties,
                        JS_DefineProperty, JS_NewObject, JS_ComputeThis};
use libc::types::common::c99::{int8_t, int16_t, int32_t, int64_t, uint8_t,
                                  uint16_t, uint32_t, uint64_t};
use glue::bindgen::{RUST_JSVAL_TO_OBJECT, RUST_JSVAL_IS_PRIMITIVE};
use rust::jsobj;

export JSOPTION_STRICT;
export JSOPTION_WERROR;
export JSOPTION_VAROBJFIX;
export JSOPTION_METHODJIT;

export JSPROP_ENUMERATE;
export JSPROP_SHARED;
export JSPROP_NATIVE_ACCESSORS;

export JSCLASS_GLOBAL_FLAGS;
export JSCLASS_HAS_RESERVED_SLOTS;

export rust;
export name_pool;

export jsapi;
export global;
export glue;
export crust;

export ptr_methods;

// These are just macros in jsapi.h
use JS_NewRuntime = jsapi::bindgen::JS_Init;
export JS_NewRuntime;
use JS_DestroyRuntime = jsapi::bindgen::JS_Finish;
export JS_DestroyRuntime;
/*
FIXME: Not sure where JS_Lock is
use JS_LockRuntime = jsapi::bindgen::JS_Lock;
export JS_LockRuntime;
use JS_UnlockRuntime = jsapi::bindgen::JS_Unlock;
export JS_UnlockRuntime;
*/

export JS_ARGV;
export JS_SET_RVAL;
export JS_THIS_OBJECT;
export JSVAL_VOID;
export JSVAL_NULL;
export JSVAL_ZERO;
export JSVAL_ONE;
export JSVAL_FALSE;
export JSVAL_TRUE;

// FIXME: Add the remaining options
const JSOPTION_STRICT: uint32_t =    0b00000000000001u32;
const JSOPTION_WERROR: uint32_t =    0b00000000000010u32;
const JSOPTION_VAROBJFIX: uint32_t = 0b00000000000100u32;
//const JSOPTION_METHODJIT: uint32_t = 0b100000000000000u32;
const JSOPTION_METHODJIT: uint32_t = (1 << 14) as u32;

const default_heapsize: u32 = 8_u32 * 1024_u32 * 1024_u32;
const default_stacksize: uint = 8192u;
const ERR: JSBool = 0_i32;

const JSVAL_TAG_MAX_DOUBLE: u64 = 0x1FFF0;

const JSVAL_TYPE_DOUBLE: u64 = 0x00;
const JSVAL_TYPE_INT32: u64 = 0x01;
const JSVAL_TYPE_UNDEFINED: u64 = 0x02;
const JSVAL_TYPE_BOOLEAN: u64 = 0x03;
const JSVAL_TYPE_MAGIC: u64 = 0x04;
const JSVAL_TYPE_STRING: u64 = 0x05;
const JSVAL_TYPE_NULL: u64 = 0x06;
const JSVAL_TYPE_OBJECT: u64 = 0x07;
const JSVAL_TYPE_UNKNOWN: u64 = 0x20;

const JSVAL_TAG_SHIFT: int = 47;

//The following constants are totally broken on non-64bit platforms.
//See jsapi.h for the proper macro definitions.
const JSVAL_VOID: u64 = (JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNKNOWN) << JSVAL_TAG_SHIFT;
const JSVAL_NULL: u64 = (JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL) << JSVAL_TAG_SHIFT;
const JSVAL_ZERO: u64 = (JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32) << JSVAL_TAG_SHIFT;
const JSVAL_ONE: u64 = ((JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32) << JSVAL_TAG_SHIFT) | 1;
const JSVAL_FALSE: u64 = (JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN) << JSVAL_TAG_SHIFT;
const JSVAL_TRUE: u64 = ((JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN) << JSVAL_TAG_SHIFT) | 1;

const JSPROP_ENUMERATE: c_uint = 0x01;
const JSPROP_READONLY: c_uint  = 0x02;
const JSPROP_SHARED: c_uint =    0x40;
const JSPROP_NATIVE_ACCESSORS: c_uint = 0x08;

const JSCLASS_RESERVED_SLOTS_SHIFT: c_uint = 8;
const JSCLASS_RESERVED_SLOTS_WIDTH: c_uint = 8;
const JSCLASS_RESERVED_SLOTS_MASK: c_uint = ((1 << JSCLASS_RESERVED_SLOTS_WIDTH) - 1);

const JSCLASS_HIGH_FLAGS_SHIFT: c_uint =
    JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH;
const JSCLASS_IS_GLOBAL: c_uint = (1<<(JSCLASS_HIGH_FLAGS_SHIFT+1));

const JSCLASS_GLOBAL_SLOT_COUNT: c_uint = JSProto_LIMIT * 3 + 24;

pure fn JSCLASS_HAS_RESERVED_SLOTS(n: c_uint) -> c_uint {
    (n & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT
}

fn result(n: JSBool) -> Result<(),()> {
    if n != ERR {Ok(())} else {Err(())}
}
fn result_obj(o: jsobj) -> Result<jsobj, ()> {
    if o.ptr != null() {Ok(o)} else {Err(())}
}

type named_functions = @{
    names: ~[~str],
    funcs: ~[JSFunctionSpec]
};

#[inline(always)]
unsafe fn JS_ARGV(_cx: *JSContext, vp: *jsval) -> *jsval {
    ptr::offset(vp, 2u)
}

unsafe fn JS_SET_RVAL(_cx: *JSContext, vp: *jsval, v: jsval) {
    let vp: *mut jsval = cast::reinterpret_cast(&vp);
    *vp = v;
}

#[inline(always)]
unsafe fn JS_THIS_OBJECT(cx: *JSContext, vp: *jsval) -> *JSObject unsafe {
    let r = RUST_JSVAL_TO_OBJECT(
        if RUST_JSVAL_IS_PRIMITIVE(*ptr::offset(vp, 1)) == 0 {
            JS_ComputeThis(cx, vp)
        } else {
            *ptr::offset(vp, 1)
        });
    r
}

<|endoftext|>


<commit_before>fn main() {
    let mut mutable_integer = 7i32;

    {
        // Borrow `mutable_integer`
        let large_integer = &mutable_integer;

        // Error! `mutable_integer` is frozen in this scope
        mutable_integer = 50;
        // FIXME ^ Comment out this line

        // `large_integer` goes out of scope
    }

    // Ok! `mutable_integer` is not frozen in this scope
    mutable_integer = 3;
}
<commit_msg>Freeze: Prefix variables with "_" to avoid compiler warnings<commit_after>fn main() {
    let mut _mutable_integer = 7i32;

    {
        // Borrow `_mutable_integer`
        let _large_integer = &_mutable_integer;

        // Error! `_mutable_integer` is frozen in this scope
        _mutable_integer = 50;
        // FIXME ^ Comment out this line

        // `_large_integer` goes out of scope
    }

    // Ok! `_mutable_integer` is not frozen in this scope
    _mutable_integer = 3;
}
<|endoftext|>