<commit_before>use ffi;
use std::os::raw::c_int;
use std::ptr;
use types::*;
use ffi::MaybeError;
use device::DeviceInfo;

/// Represents the input port of a PortMidi device.
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl InputPort {
    /// Construct a new `InputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an input device an `Error::NotAnInputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
        if device.is_output() {
            return Err(Error::NotAnInputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenInput(&raw_stream as *const *const _,
                              device.id(),
                              ptr::null(), // *inputDriverInfo, not needed for normal operation
                              buffer_size as c_int,
                              ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                              ptr::null()) // time_info, a pointer passed to the time procedure
        }));

        Ok(InputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Returns a `Vec<MidiEvent>` with at most `cnt` elements.
    /// If there was no Midi event available, `None` is returned.
    /// If PortMidi fails to read from the device an `Error::PortMidi(_)` is returned.
    pub fn read_n(&self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > self.buffer_size {
            self.buffer_size as c_int
        } else {
            cnt as c_int
        };
        let mut event_buffer = vec![ffi::PmEvent::default(); self.buffer_size];
        let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
        ::std::thread::sleep_ms(20);
        match ffi::PmError::try_from(res) {
            Ok(event_cnt) => {
                let events = (0..event_cnt as usize)
                                 .map(|i| MidiEvent::from(event_buffer[i].clone()))
                                 .collect::<Vec<MidiEvent>>();
                Ok(Some(events))
            }
            err @ Err(ffi::PmError::PmNoError) => Ok(None),
            Err(err) => return Err(Error::PortMidi(err)),
        }
    }

    /// Reads a single `MidiEvent` if one is avaible.
    ///
    /// A `Result` of `None` means no event was available.
    pub fn read(&mut self) -> Result<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// Polls for available Midi events.
    /// Returns `true` if there are events available, otherwise `false` is returned.
    /// If the polling fails an `Error::PortMidi(_)` is returned.
    pub fn poll(&self) -> Result<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            err @ _ => Err(Error::PortMidi(err)),
        }
    }
}
impl Drop for InputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}

/// Representation the output port of a PortMidi device.
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl OutputPort {
    /// Construct a new `OutputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an output device an `Error::NotAnOutputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<OutputPort> {
        if device.is_input() {
            return Err(Error::NotAnOutputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenOutput(&raw_stream as *const *const _,
                               device.id(),
                               ptr::null(), // *inputDriverInfo, not needed for normal operation
                               buffer_size as c_int,
                               ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                               ptr::null(), // time_info, a pointer passed to the time procedure
                               0) //latency
        }));

        Ok(OutputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Terminates outgoing messages immediately.
    ///
    /// The caller should immediately close the output port, this may
    /// result in transmission of a partial midi message. Note, not all platforms
    /// support abort.
    ///
    /// NOTE: This is unsafe, either mark the device as invalid or try to reopen it afterwards.
    fn abort(&mut self) -> Result<()> {
        Result::from(unsafe { ffi::Pm_Abort(self.stream) })
    }

    /// Write a single `MidiEvent`
    pub fn write_event(&mut self, midi_event: MidiEvent) -> Result<()> {
        let event = midi_event.into();
        Result::from(unsafe { ffi::Pm_Write(self.stream, &event, 1) })
    }

    /// Write a single `MidiMessage`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_message(&mut self, midi_message: MidiMessage) -> Result<()> {
        let message = midi_message.into();
        Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, message) })
    }
}
impl Drop for OutputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}
<commit_msg>Implement `write_events` which writes a buffer of midi events.<commit_after>use ffi;
use std::os::raw::c_int;
use std::ptr;
use types::*;
use ffi::MaybeError;
use device::DeviceInfo;

/// Represents the input port of a PortMidi device.
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl InputPort {
    /// Construct a new `InputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an input device an `Error::NotAnInputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
        if device.is_output() {
            return Err(Error::NotAnInputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenInput(&raw_stream as *const *const _,
                              device.id(),
                              ptr::null(), // *inputDriverInfo, not needed for normal operation
                              buffer_size as c_int,
                              ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                              ptr::null()) // time_info, a pointer passed to the time procedure
        }));

        Ok(InputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Returns a `Vec<MidiEvent>` with at most `cnt` elements.
    /// If there was no Midi event available, `None` is returned.
    /// If PortMidi fails to read from the device an `Error::PortMidi(_)` is returned.
    pub fn read_n(&self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > self.buffer_size {
            self.buffer_size as c_int
        } else {
            cnt as c_int
        };
        let mut event_buffer = vec![ffi::PmEvent::default(); self.buffer_size];
        let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
        ::std::thread::sleep_ms(20);
        match ffi::PmError::try_from(res) {
            Ok(event_cnt) => {
                let events = (0..event_cnt as usize)
                                 .map(|i| MidiEvent::from(event_buffer[i].clone()))
                                 .collect::<Vec<MidiEvent>>();
                Ok(Some(events))
            }
            err @ Err(ffi::PmError::PmNoError) => Ok(None),
            Err(err) => return Err(Error::PortMidi(err)),
        }
    }

    /// Reads a single `MidiEvent` if one is avaible.
    ///
    /// A `Result` of `None` means no event was available.
    pub fn read(&mut self) -> Result<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// Polls for available Midi events.
    /// Returns `true` if there are events available, otherwise `false` is returned.
    /// If the polling fails an `Error::PortMidi(_)` is returned.
    pub fn poll(&self) -> Result<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            err @ _ => Err(Error::PortMidi(err)),
        }
    }
}
impl Drop for InputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}

/// Representation the output port of a PortMidi device.
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl OutputPort {
    /// Construct a new `OutputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an output device an `Error::NotAnOutputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<OutputPort> {
        if device.is_input() {
            return Err(Error::NotAnOutputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenOutput(&raw_stream as *const *const _,
                               device.id(),
                               ptr::null(), // *inputDriverInfo, not needed for normal operation
                               buffer_size as c_int,
                               ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                               ptr::null(), // time_info, a pointer passed to the time procedure
                               0) //latency
        }));

        Ok(OutputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Terminates outgoing messages immediately.
    ///
    /// The caller should immediately close the output port, this may
    /// result in transmission of a partial midi message. Note, not all platforms
    /// support abort.
    ///
    /// NOTE: This is unsafe, either mark the device as invalid or try to reopen it afterwards.
    fn abort(&mut self) -> Result<()> {
        Result::from(unsafe { ffi::Pm_Abort(self.stream) })
    }

    /// Write a single `MidiEvent`
    pub fn write_event(&mut self, midi_event: MidiEvent) -> Result<()> {
        let event = midi_event.into();
        Result::from(unsafe { ffi::Pm_Write(self.stream, &event, 1) })

    /// Write a buffer of midi events to the output port.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_events<T: Into<MidiEvent>>(&mut self, midi_events: Vec<T>) -> Result<()> {
        let events: Vec<ffi::PmEvent> = midi_events.into_iter()
                                                   .map(|event| event.into().into())
                                                   .collect();
        Result::from(unsafe { ffi::Pm_Write(self.stream, events.as_ptr(), events.len() as c_int) })
    }

    /// Write a single `MidiMessage`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_message(&mut self, midi_message: MidiMessage) -> Result<()> {
        let message = midi_message.into();
        Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, message) })
    }
}
impl Drop for OutputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}
<|endoftext|>


<commit_before>pub fn pathmatch(pattern: &str, pathstring: &str) -> bool
{
    let mut pattern_chars = pattern.chars();
    let mut path_chars = pathstring.chars();
    loop {
        match pattern_chars.next() {
            None => return path_chars.next().is_none(),
            Some('?') => if path_chars.next().is_none() { return false; },
            Some(pc) => {
                match path_chars.next() {
                    None => return false,
                    Some(sc) => if pc != sc { return false },
                }
            }
        }
    }
}

#[test]
fn pathmatch_test_anychar()
{
    assert!(pathmatch("?", "?"));
    assert!(pathmatch("?", "a"));
    assert!(pathmatch("??", "BC"));
    assert!(pathmatch("B?", "BC"));
    assert!(pathmatch("?C", "BC"));
    assert!(!pathmatch("?", ""));
    assert!(!pathmatch("D?", "BC"));
    assert!(!pathmatch("?E", "BC"));
}

#[test]
fn pathmatch_test_exact_equality()
{
    assert!(pathmatch("", ""));
    assert!(pathmatch("a", "a"));
    assert!(pathmatch("BC", "BC"));
    assert!(!pathmatch("a", ""));
    assert!(!pathmatch("", "BC"));
}

<commit_msg>any characters wildcard `*`<commit_after>pub fn pathmatch(pattern: &str, pathstring: &str) -> bool
{
    use std::str::Chars;
    let pattern_chars = pattern.chars();
    let path_chars = pathstring.chars();
    return pathmatch_impl(pattern_chars, path_chars);

    fn pathmatch_impl(mut pattern_chars: Chars, mut path_chars: Chars) -> bool
    {
        loop {
            match pattern_chars.next() {
                None => return path_chars.next().is_none(),
                Some('?') => if path_chars.next().is_none() { return false; },
                Some('*') => loop {
                    if pathmatch_impl(pattern_chars, path_chars) {
                        return true;
                    }
                    if path_chars.next().is_none() {
                        break;
                    }
                },
                Some(pc) => {
                    match path_chars.next() {
                        None => return false,
                        Some(sc) => if pc != sc { return false },
                    }
                }
            }
        }
    }
}

#[test]
fn pathmatch_test_anyname()
{
    assert!(pathmatch("*", ""));
    assert!(pathmatch("*", "?"));
    assert!(pathmatch("*", "d?F"));
    assert!(pathmatch("a*", "a"));
    assert!(pathmatch("a*", "abcdef"));
    assert!(pathmatch("*f", "abcdef"));
    assert!(pathmatch("a*f", "abcdef"));
    assert!(pathmatch("*cd*", "abcdef"));
    assert!(pathmatch("a*cd*f", "abcdef"));
    assert!(pathmatch("acdf", "acdf"));
    assert!(!pathmatch("*a", "abc"));
    assert!(!pathmatch("c*", "abc"));
}

#[test]
fn pathmatch_test_anychar()
{
    assert!(pathmatch("?", "?"));
    assert!(pathmatch("?", "a"));
    assert!(pathmatch("??", "BC"));
    assert!(pathmatch("B?", "BC"));
    assert!(pathmatch("?C", "BC"));
    assert!(!pathmatch("?", ""));
    assert!(!pathmatch("D?", "BC"));
    assert!(!pathmatch("?E", "BC"));
}

#[test]
fn pathmatch_test_exact_equality()
{
    assert!(pathmatch("", ""));
    assert!(pathmatch("a", "a"));
    assert!(pathmatch("BC", "BC"));
    assert!(!pathmatch("a", ""));
    assert!(!pathmatch("", "BC"));
}

<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    tests::suite, vault::VaultStorage, Capability, Error, Identity, KVStorage, Permission, Policy,
    Value,
};

const VAULT_HOST: &str = "http://localhost:8200";
const VAULT_ROOT_TOKEN: &str = "root_token";

/// A test for verifying VaultStorage properly implements the LibraSecureStorage API. This test
/// depends on running Vault, which can be done by using the provided docker run script in
/// `docker/vault/run.sh`
#[test]
#[ignore]
fn execute_storage_tests_vault() {
    let mut storage = VaultStorage::new(VAULT_HOST.into(), VAULT_ROOT_TOKEN.into(), None);
    storage.reset_and_clear().unwrap();

    test_vault(&mut storage);
    suite::execute_all_storage_tests(&mut storage);
    storage.reset_and_clear().unwrap();
}

#[test]
#[ignore]
fn execute_storage_tests_vault_with_namespace() {
    let mut storage = VaultStorage::new(
        VAULT_HOST.into(),
        VAULT_ROOT_TOKEN.into(),
        Some("test".into()),
    );
    let mut storage1 = VaultStorage::new(
        VAULT_HOST.into(),
        VAULT_ROOT_TOKEN.into(),
        Some("test1".into()),
    );
    storage.reset_and_clear().unwrap();

    test_vault(&mut storage);
    test_vault(&mut storage1);
    suite::execute_all_storage_tests(&mut storage);
    suite::execute_all_storage_tests(&mut storage1);
    storage.reset_and_clear().unwrap();
}

/// Creates and returns a new VaultStorage instance for testing purposes.
pub fn test_vault(storage: &mut VaultStorage) {
    // TODO(davidiw,joshlind): evaluate other systems and determine if create_token can be on the
    // Storage / KV interface. And then refactor this method to make it cleaner and easier to reason
    // about.
    let reader: String = "reader".into();
    let writer: String = "writer".into();

    let anyone = Policy::public();
    let root = Policy::new(vec![]);
    let partial = Policy::new(vec![
        Permission::new(Identity::User(reader.clone()), vec![Capability::Read]),
        Permission::new(
            Identity::User(writer.clone()),
            vec![Capability::Read, Capability::Write],
        ),
    ]);
    let full = Policy::new(vec![
        Permission::new(
            Identity::User(reader.clone()),
            vec![Capability::Read, Capability::Write],
        ),
        Permission::new(
            Identity::User(writer.clone()),
            vec![Capability::Read, Capability::Write],
        ),
    ]);

    // Initialize data and policies

    storage.create("anyone", Value::U64(1), &anyone).unwrap();
    storage.create("root", Value::U64(2), &root).unwrap();
    storage.create("partial", Value::U64(3), &partial).unwrap();
    storage.create("full", Value::U64(4), &full).unwrap();

    // Verify initial reading works correctly

    assert_eq!(storage.get("anyone"), Ok(Value::U64(1)));
    assert_eq!(storage.get("root"), Ok(Value::U64(2)));
    assert_eq!(storage.get("partial"), Ok(Value::U64(3)));
    assert_eq!(storage.get("full"), Ok(Value::U64(4)));

    let writer_token = storage.create_token(vec![&writer]).unwrap();
    let mut writer = VaultStorage::new(VAULT_HOST.into(), writer_token, storage.namespace());
    assert_eq!(writer.get("anyone"), Ok(Value::U64(1)));
    assert_eq!(writer.get("root"), Err(Error::PermissionDenied));
    assert_eq!(writer.get("partial"), Ok(Value::U64(3)));
    assert_eq!(writer.get("full"), Ok(Value::U64(4)));

    let reader_token = storage.create_token(vec![&reader]).unwrap();
    let mut reader = VaultStorage::new(VAULT_HOST.into(), reader_token, storage.namespace());
    assert_eq!(reader.get("anyone"), Ok(Value::U64(1)));
    assert_eq!(reader.get("root"), Err(Error::PermissionDenied));
    assert_eq!(reader.get("partial"), Ok(Value::U64(3)));
    assert_eq!(reader.get("full"), Ok(Value::U64(4)));

    // Attempt writes followed by reads for correctness

    writer.set("anyone", Value::U64(5)).unwrap();
    assert_eq!(
        writer.set("root", Value::U64(6)),
        Err(Error::PermissionDenied)
    );
    writer.set("partial", Value::U64(7)).unwrap();
    writer.set("full", Value::U64(8)).unwrap();

    assert_eq!(storage.get("anyone"), Ok(Value::U64(5)));
    assert_eq!(storage.get("root"), Ok(Value::U64(2)));
    assert_eq!(storage.get("partial"), Ok(Value::U64(7)));
    assert_eq!(storage.get("full"), Ok(Value::U64(8)));

    reader.set("anyone", Value::U64(9)).unwrap();
    assert_eq!(
        reader.set("root", Value::U64(10)),
        Err(Error::PermissionDenied)
    );
    assert_eq!(
        reader.set("partial", Value::U64(11)),
        Err(Error::PermissionDenied)
    );
    reader.set("full", Value::U64(12)).unwrap();

    assert_eq!(storage.get("anyone"), Ok(Value::U64(9)));
    assert_eq!(storage.get("root"), Ok(Value::U64(2)));
    assert_eq!(storage.get("partial"), Ok(Value::U64(7)));
    assert_eq!(storage.get("full"), Ok(Value::U64(12)));
}
<commit_msg>[storage] merge tests to avoid race condition<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    tests::suite, vault::VaultStorage, Capability, Error, Identity, KVStorage, Permission, Policy,
    Value,
};

const VAULT_HOST: &str = "http://localhost:8200";
const VAULT_ROOT_TOKEN: &str = "root_token";

/// A test for verifying VaultStorage properly implements the LibraSecureStorage API. This test
/// depends on running Vault, which can be done by using the provided docker run script in
/// `docker/vault/run.sh`
// There can only be one vault test as reset called on one instance can break another test
#[test]
#[ignore]
fn execute_storage_tests_vault() {
    let mut storage = VaultStorage::new(VAULT_HOST.into(), VAULT_ROOT_TOKEN.into(), None);
    storage.reset_and_clear().unwrap();

    test_vault(&mut storage);
    suite::execute_all_storage_tests(&mut storage);

    let mut storage0 = VaultStorage::new(
        VAULT_HOST.into(),
        VAULT_ROOT_TOKEN.into(),
        Some("test0".into()),
    );
    let mut storage1 = VaultStorage::new(
        VAULT_HOST.into(),
        VAULT_ROOT_TOKEN.into(),
        Some("test1".into()),
    );

    test_vault(&mut storage0);
    test_vault(&mut storage1);
    suite::execute_all_storage_tests(&mut storage0);
    suite::execute_all_storage_tests(&mut storage1);
    storage.reset_and_clear().unwrap();
}

/// Creates and returns a new VaultStorage instance for testing purposes.
pub fn test_vault(storage: &mut VaultStorage) {
    // TODO(davidiw,joshlind): evaluate other systems and determine if create_token can be on the
    // Storage / KV interface. And then refactor this method to make it cleaner and easier to reason
    // about.
    let reader: String = "reader".into();
    let writer: String = "writer".into();

    let anyone = Policy::public();
    let root = Policy::new(vec![]);
    let partial = Policy::new(vec![
        Permission::new(Identity::User(reader.clone()), vec![Capability::Read]),
        Permission::new(
            Identity::User(writer.clone()),
            vec![Capability::Read, Capability::Write],
        ),
    ]);
    let full = Policy::new(vec![
        Permission::new(
            Identity::User(reader.clone()),
            vec![Capability::Read, Capability::Write],
        ),
        Permission::new(
            Identity::User(writer.clone()),
            vec![Capability::Read, Capability::Write],
        ),
    ]);

    // Initialize data and policies

    storage.create("anyone", Value::U64(1), &anyone).unwrap();
    storage.create("root", Value::U64(2), &root).unwrap();
    storage.create("partial", Value::U64(3), &partial).unwrap();
    storage.create("full", Value::U64(4), &full).unwrap();

    // Verify initial reading works correctly

    assert_eq!(storage.get("anyone"), Ok(Value::U64(1)));
    assert_eq!(storage.get("root"), Ok(Value::U64(2)));
    assert_eq!(storage.get("partial"), Ok(Value::U64(3)));
    assert_eq!(storage.get("full"), Ok(Value::U64(4)));

    let writer_token = storage.create_token(vec![&writer]).unwrap();
    let mut writer = VaultStorage::new(VAULT_HOST.into(), writer_token, storage.namespace());
    assert_eq!(writer.get("anyone"), Ok(Value::U64(1)));
    assert_eq!(writer.get("root"), Err(Error::PermissionDenied));
    assert_eq!(writer.get("partial"), Ok(Value::U64(3)));
    assert_eq!(writer.get("full"), Ok(Value::U64(4)));

    let reader_token = storage.create_token(vec![&reader]).unwrap();
    let mut reader = VaultStorage::new(VAULT_HOST.into(), reader_token, storage.namespace());
    assert_eq!(reader.get("anyone"), Ok(Value::U64(1)));
    assert_eq!(reader.get("root"), Err(Error::PermissionDenied));
    assert_eq!(reader.get("partial"), Ok(Value::U64(3)));
    assert_eq!(reader.get("full"), Ok(Value::U64(4)));

    // Attempt writes followed by reads for correctness

    writer.set("anyone", Value::U64(5)).unwrap();
    assert_eq!(
        writer.set("root", Value::U64(6)),
        Err(Error::PermissionDenied)
    );
    writer.set("partial", Value::U64(7)).unwrap();
    writer.set("full", Value::U64(8)).unwrap();

    assert_eq!(storage.get("anyone"), Ok(Value::U64(5)));
    assert_eq!(storage.get("root"), Ok(Value::U64(2)));
    assert_eq!(storage.get("partial"), Ok(Value::U64(7)));
    assert_eq!(storage.get("full"), Ok(Value::U64(8)));

    reader.set("anyone", Value::U64(9)).unwrap();
    assert_eq!(
        reader.set("root", Value::U64(10)),
        Err(Error::PermissionDenied)
    );
    assert_eq!(
        reader.set("partial", Value::U64(11)),
        Err(Error::PermissionDenied)
    );
    reader.set("full", Value::U64(12)).unwrap();

    assert_eq!(storage.get("anyone"), Ok(Value::U64(9)));
    assert_eq!(storage.get("root"), Ok(Value::U64(2)));
    assert_eq!(storage.get("partial"), Ok(Value::U64(7)));
    assert_eq!(storage.get("full"), Ok(Value::U64(12)));
}
<|endoftext|>


<commit_before>extern crate handlebars;
extern crate rustc_serialize;
extern crate pulldown_cmark;

use renderer::Renderer;
use book::{BookItems, BookConfig};
use theme;

use std::path::{Path, PathBuf, Component};
use std::fs::{self, File, metadata};
use std::error::Error;
use std::io::{self, Read, Write};
use std::collections::BTreeMap;

use self::handlebars::{Handlebars, HelperDef, RenderError, RenderContext, Helper, Context, JsonRender};
use self::rustc_serialize::json::{self, Json, ToJson};
use self::pulldown_cmark::Parser;
use self::pulldown_cmark::html;

pub struct HtmlHandlebars;

impl Renderer for HtmlHandlebars {
    fn render(&self, book: BookItems, config: &BookConfig) -> Result<(), Box<Error>> {

        let mut handlebars = Handlebars::new();

        // Load template
        let t = theme::get_index_hbs();

        // Register template
        try!(handlebars.register_template_string("index", t.to_owned()));

        // Register helper
        handlebars.register_helper("toc", Box::new(RenderToc));

        let mut data = try!(make_data(book.clone(), config));

        // Render a file for every entry in the book
        let mut index = true;
        for (_, item) in book {

            if item.path != PathBuf::new() {

                let path = config.src().join(&item.path);
                println!("Open file: {:?}", path);
                let mut f = try!(File::open(&path));
                let mut content: String = String::new();

                try!(f.read_to_string(&mut content));

                // Render markdown using the pulldown-cmark
                content = render_html(&content);

                // Remove content from previous file and render content for this one
                data.remove("content");
                data.insert("content".to_string(), content.to_json());

                // Remove path to root from previous file and render content for this one
                data.remove("path_to_root");
                data.insert("path_to_root".to_string(), path_to_root(&item.path).to_json());

                // Rendere the handlebars template with the data
                let rendered = try!(handlebars.render("index", &data));

                // Write to file
                let mut file = try!(create_file(config.dest(), &item.path));
                try!(file.write_all(&rendered.into_bytes()));

                // Create an index.html from the first element in SUMMARY.md
                if index {
                    try!(fs::copy(
                        config.dest().join(path_to_link(&item.path).expect("Failed at creation of index.html")),
                        config.dest().join("index.html")
                    ));
                    index = false;
                }
            }
        }

        // Copy static files (js, css, images, ...)

        // JavaScript
        let mut js_file = try!(File::create(config.dest().join("book.js")));
        try!(js_file.write_all(theme::get_js()));

        // Css
        let mut css_file = try!(File::create(config.dest().join("book.css")));
        try!(css_file.write_all(theme::get_css()));

        Ok(())
    }
}

impl HtmlHandlebars {
    pub fn new() -> Self {
        HtmlHandlebars
    }

    fn _load_template(&self, path: &Path) -> Result<String, Box<Error>> {
        let mut file = try!(File::open(path));
        let mut s = String::new();
        try!(file.read_to_string(&mut s));
        Ok(s)
    }
}

fn create_file(working_directory: &Path, path: &Path) -> Result<File, Box<Error>> {

    println!("create_file:\n\t{:?}\n\t{:?}", working_directory, path);

    // Extract filename
    let mut file_name;
    if let Some(name) = path.file_stem() {
        file_name = String::from(name.to_str().unwrap());
    }
    else { return Err(Box::new(io::Error::new(io::ErrorKind::Other, "No filename"))) }

    file_name.push_str(".html");

    // Delete filename from path
    let mut path = path.to_path_buf();
    path.pop();

    // Create directories if they do not exist
    let mut constructed_path = PathBuf::from(working_directory);

    for component in path.components() {

        let mut dir;
        match component {
            Component::Normal(_) => { dir = PathBuf::from(component.as_os_str()); },
            _ => continue,
        }

        constructed_path.push(&dir);

        println!("constructed path= {:?}\ndir= {:?}", constructed_path, dir.as_os_str());

        // Check if path exists
        match metadata(&constructed_path) {
            // Any way to combine the Err and first Ok branch ??
            Err(_) => {
                try!(fs::create_dir(&constructed_path))
            },
            Ok(f) => {
                if !f.is_dir() {
                    try!(fs::create_dir(&constructed_path))
                } else {
                    println!("Exists ??");
                    continue
                }
            },
        }

    }

    let file = try!(File::create(
        constructed_path.join(file_name)
    ));

    Ok(file)
}

fn make_data(book: BookItems, config: &BookConfig) -> Result<BTreeMap<String,Json>, Box<Error>> {

    /*
        Function to make the JSon data for the handlebars template:

        {
            "language": ...,
            "title": ...
            "chapters": [
                {
                    "section": section,
                    "chapter": BookItem,
                },
                {
                    ...
                },
            ],
        }

    */

    let mut data  = BTreeMap::new();
    data.insert("language".to_string(), "en".to_json());
    data.insert("title".to_string(), config.title.to_json());

    let mut chapters = vec![];

    for (section, item) in book {
        let mut chapter = BTreeMap::new();
        chapter.insert("section".to_string(), section.to_json());
        chapter.insert("name".to_string(), item.name.to_json());
        chapter.insert("path".to_string(), item.path.to_str().unwrap().to_json());

        chapters.push(chapter);
    }

    data.insert("chapters".to_string(), chapters.to_json());

    Ok(data)
}

fn render_html(text: &str) -> String {
    let mut s = String::with_capacity(text.len() * 3 / 2);
    let p = Parser::new(&text);
    html::push_html(&mut s, p);
    s
}

fn path_to_link(path: &Path) -> Option<PathBuf> {
    // Extract filename
    let mut file_name;
    if let Some(name) = path.file_stem() {
        file_name = String::from(name.to_str().unwrap());
    }
    else { return None }

    file_name.push_str(".html");

    // Change file name to .html
    let mut path = path.to_path_buf();
    path.set_file_name(file_name);

    // Clean paths with './'

    Some(path)
}

fn path_to_root(path: &Path) -> String {
    // Remove filename and add "../" for every directory

    path.to_path_buf().parent().expect("")
        .components().fold(String::new(), |mut s, c| {
            match c {
                Component::Normal(_) => s.push_str("../"),
                _ => {}
            }
            s
        })
}

// Handlebars helper to construct TOC
#[derive(Clone, Copy)]
struct RenderToc;

impl HelperDef for RenderToc {
  fn call(&self, c: &Context, _h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {

    // get value from context data
    // rc.get_path() is current json parent path, you should always use it like this
    // param is the key of value you want to display
    let chapters = c.navigate(rc.get_path(), "chapters");
    let path_to_root = c.navigate(rc.get_path(), "path_to_root").to_string().replace("\"", "");
    try!(rc.writer.write("
".as_bytes()));

    // Decode json format
    let decoded: Vec<BTreeMap<String,String>> = json::decode(&chapters.to_string()).unwrap();

    let mut current_level = 1;

    for item in decoded {

        let level = item.get("section").expect("Error: section should be Some(_)").len() / 2;
        if level > current_level {
            try!(rc.writer.write("
".as_bytes()));
            try!(rc.writer.write("
".as_bytes()));
            try!(rc.writer.write("
".as_bytes()));
        } else if level < current_level {
            try!(rc.writer.write("
".as_bytes()));
            try!(rc.writer.write("
".as_bytes()));
        }
        else {
            try!(rc.writer.write("
".as_bytes()));
        }

        // Link
        let path_exists = if let Some(path) = item.get("path") {
            if path.len() > 0 {
                try!(rc.writer.write("".as_bytes()));
                true
            } else {
                false
            }
        }else {
            false
        };

        try!(rc.writer.write("".as_bytes()));
        try!(rc.writer.write(item.get("section").expect("Error: section should be Some(_)").as_bytes()));
        try!(rc.writer.write(" ".as_bytes()));
        try!(rc.writer.write(item.get("name").expect("Error: name should be Some(_)").as_bytes()));

        if path_exists {
            try!(rc.writer.write("".as_bytes()));
        }

        try!(rc.writer.write("
".as_bytes()));

        current_level = level;
    }

    try!(rc.writer.write("
".as_bytes()));
    Ok(())
  }
}
<commit_msg>Clean up: Removed uneeded function because the same functionality is present in std<commit_after>extern crate handlebars;
extern crate rustc_serialize;
extern crate pulldown_cmark;

use renderer::Renderer;
use book::{BookItems, BookConfig};
use theme;

use std::path::{Path, PathBuf, Component};
use std::fs::{self, File, metadata};
use std::error::Error;
use std::io::{self, Read, Write};
use std::collections::BTreeMap;

use self::handlebars::{Handlebars, HelperDef, RenderError, RenderContext, Helper, Context, JsonRender};
use self::rustc_serialize::json::{self, Json, ToJson};
use self::pulldown_cmark::Parser;
use self::pulldown_cmark::html;

pub struct HtmlHandlebars;

impl Renderer for HtmlHandlebars {
    fn render(&self, book: BookItems, config: &BookConfig) -> Result<(), Box<Error>> {

        let mut handlebars = Handlebars::new();

        // Load template
        let t = theme::get_index_hbs();

        // Register template
        try!(handlebars.register_template_string("index", t.to_owned()));

        // Register helper
        handlebars.register_helper("toc", Box::new(RenderToc));

        let mut data = try!(make_data(book.clone(), config));

        // Render a file for every entry in the book
        let mut index = true;
        for (_, item) in book {

            if item.path != PathBuf::new() {

                let path = config.src().join(&item.path);

                let mut f = try!(File::open(&path));
                let mut content: String = String::new();

                try!(f.read_to_string(&mut content));

                // Render markdown using the pulldown-cmark
                content = render_html(&content);

                // Remove content from previous file and render content for this one
                data.remove("content");
                data.insert("content".to_string(), content.to_json());

                // Remove path to root from previous file and render content for this one
                data.remove("path_to_root");
                data.insert("path_to_root".to_string(), path_to_root(&item.path).to_json());

                // Rendere the handlebars template with the data
                let rendered = try!(handlebars.render("index", &data));

                // Write to file
                let mut file = try!(create_file(config.dest(), &item.path));
                try!(file.write_all(&rendered.into_bytes()));

                // Create an index.html from the first element in SUMMARY.md
                if index {
                    print!(
                        "Creating index.html from {:?}",
                        config.dest().join(&item.path.with_extension("html"))
                        );

                    try!(fs::copy(
                        config.dest().join(&item.path.with_extension("html")),
                        config.dest().join("index.html")
                    ));
                    println!(" ✓");
                    index = false;
                }
            }
        }

        // Copy static files (js, css, images, ...)

        // JavaScript
        let mut js_file = try!(File::create(config.dest().join("book.js")));
        try!(js_file.write_all(theme::get_js()));

        // Css
        let mut css_file = try!(File::create(config.dest().join("book.css")));
        try!(css_file.write_all(theme::get_css()));

        Ok(())
    }
}

impl HtmlHandlebars {
    pub fn new() -> Self {
        HtmlHandlebars
    }

    fn _load_template(&self, path: &Path) -> Result<String, Box<Error>> {
        let mut file = try!(File::open(path));
        let mut s = String::new();
        try!(file.read_to_string(&mut s));
        Ok(s)
    }
}

fn create_file(working_directory: &Path, path: &Path) -> Result<File, Box<Error>> {

    // Extract filename
    let mut file_name;
    if let Some(name) = path.file_stem() {
        file_name = String::from(name.to_str().unwrap());
    }
    else { return Err(Box::new(io::Error::new(io::ErrorKind::Other, "No filename"))) }

    file_name.push_str(".html");

    // Delete filename from path
    let mut path = path.to_path_buf();
    path.pop();

    // Create directories if they do not exist
    let mut constructed_path = PathBuf::from(working_directory);

    for component in path.components() {

        let mut dir;
        match component {
            Component::Normal(_) => { dir = PathBuf::from(component.as_os_str()); },
            _ => continue,
        }

        constructed_path.push(&dir);

        // Check if path exists
        match metadata(&constructed_path) {
            // Any way to combine the Err and first Ok branch ??
            Err(_) => {
                try!(fs::create_dir(&constructed_path))
            },
            Ok(f) => {
                if !f.is_dir() {
                    try!(fs::create_dir(&constructed_path))
                } else {
                    continue
                }
            },
        }

    }

    print!("Create file: {:?}", constructed_path.join(&file_name));
    let file = try!(File::create(
        constructed_path.join(&file_name)
    ));
    println!(" ✓");

    Ok(file)
}

fn make_data(book: BookItems, config: &BookConfig) -> Result<BTreeMap<String,Json>, Box<Error>> {

    /*
        Function to make the JSon data for the handlebars template:

        {
            "language": ...,
            "title": ...
            "chapters": [
                {
                    "section": section,
                    "chapter": BookItem,
                },
                {
                    ...
                },
            ],
        }

    */

    let mut data  = BTreeMap::new();
    data.insert("language".to_string(), "en".to_json());
    data.insert("title".to_string(), config.title.to_json());

    let mut chapters = vec![];

    for (section, item) in book {
        let mut chapter = BTreeMap::new();
        chapter.insert("section".to_string(), section.to_json());
        chapter.insert("name".to_string(), item.name.to_json());
        chapter.insert("path".to_string(), item.path.to_str().unwrap().to_json());

        chapters.push(chapter);
    }

    data.insert("chapters".to_string(), chapters.to_json());

    Ok(data)
}

fn render_html(text: &str) -> String {
    let mut s = String::with_capacity(text.len() * 3 / 2);
    let p = Parser::new(&text);
    html::push_html(&mut s, p);
    s
}

fn path_to_root(path: &Path) -> String {
    // Remove filename and add "../" for every directory

    path.to_path_buf().parent().expect("")
        .components().fold(String::new(), |mut s, c| {
            match c {
                Component::Normal(_) => s.push_str("../"),
                _ => {}
            }
            s
        })
}

// Handlebars helper to construct TOC
#[derive(Clone, Copy)]
struct RenderToc;

impl HelperDef for RenderToc {
  fn call(&self, c: &Context, _h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {

    // get value from context data
    // rc.get_path() is current json parent path, you should always use it like this
    // param is the key of value you want to display
    let chapters = c.navigate(rc.get_path(), "chapters");
    let path_to_root = c.navigate(rc.get_path(), "path_to_root").to_string().replace("\"", "");
    try!(rc.writer.write("
".as_bytes()));

    // Decode json format
    let decoded: Vec<BTreeMap<String,String>> = json::decode(&chapters.to_string()).unwrap();

    let mut current_level = 1;

    for item in decoded {

        let level = item.get("section").expect("Error: section should be Some(_)").len() / 2;
        if level > current_level {
            try!(rc.writer.write("
".as_bytes()));
            try!(rc.writer.write("
".as_bytes()));
            try!(rc.writer.write("
".as_bytes()));
        } else if level < current_level {
            try!(rc.writer.write("
".as_bytes()));
            try!(rc.writer.write("
".as_bytes()));
        }
        else {
            try!(rc.writer.write("
".as_bytes()));
        }

        // Link
        let path_exists = if let Some(path) = item.get("path") {
            if path.len() > 0 {
                try!(rc.writer.write("<a href=\"".as_bytes()));

                // Prefix with path to root
                try!(rc.writer.write(path_to_root.as_bytes()));

                // Add link
                try!(rc.writer.write(
                    Path::new(
                        item.get("path")
                            .expect("Error: path should be Some(_)")
                        ).with_extension("html")
                        .to_str().unwrap().as_bytes()
                    ));

                try!(rc.writer.write("\">".as_bytes()));
                true
            } else {
                false
            }
        }else {
            false
        };

        try!(rc.writer.write("".as_bytes()));
        try!(rc.writer.write(item.get("section").expect("Error: section should be Some(_)").as_bytes()));
        try!(rc.writer.write(" ".as_bytes()));
        try!(rc.writer.write(item.get("name").expect("Error: name should be Some(_)").as_bytes()));

        if path_exists {
            try!(rc.writer.write("".as_bytes()));
        }

        try!(rc.writer.write("
".as_bytes()));

        current_level = level;
    }

    try!(rc.writer.write("
".as_bytes()));
    Ok(())
  }
}
<|endoftext|>


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

use crate::types::TypeName;
use indoc::indoc;
use lazy_static::lazy_static;
use proc_macro2::Span;
use std::collections::HashMap;
use syn::{parse_quote, Ident, TypePath};

/// Whether this type should be included in the 'prelude'
/// passed to bindgen, and if so, how.
#[derive(Debug)]
enum PreludePolicy {
    Exclude,
    IncludeNormal,
    IncludeTemplated,
}

/// Details about known special types, mostly primitives.
#[derive(Debug)]
struct TypeDetails {
    /// The name used by cxx (in Rust code) for this type.
    rs_name: String,
    /// C++ equivalent name for a Rust type.
    cpp_name: String,
    /// Whether this can be safely represented by value.
    by_value_safe: bool,
    /// Whether and how to include this in the prelude given to bindgen.
    prelude_policy: PreludePolicy,
    /// Whether this is a & on the Rust side but a value on the C++
    /// side. Only applies to &str.
    de_referencicate: bool,
}

impl TypeDetails {
    fn new(
        rs_name: String,
        cpp_name: String,
        by_value_safe: bool,
        prelude_policy: PreludePolicy,
        de_referencicate: bool,
    ) -> Self {
        TypeDetails {
            rs_name,
            cpp_name,
            by_value_safe,
            prelude_policy,
            de_referencicate,
        }
    }

    fn get_prelude_entry(&self) -> Option<String> {
        match self.prelude_policy {
            PreludePolicy::Exclude => None,
            PreludePolicy::IncludeNormal | PreludePolicy::IncludeTemplated => {
                let cxx_name = &self.rs_name;
                let (templating, payload) = match self.prelude_policy {
                    PreludePolicy::IncludeNormal => ("", "char* ptr"),
                    PreludePolicy::IncludeTemplated => ("template<typename T> ", "T* ptr"),
                    _ => unreachable!(),
                };
                Some(format!(
                    indoc! {"
                    /**
                    *

                    */
                    {}class {} {{
                        {};
                    }};

                    "},
                    self.cpp_name, templating, cxx_name, payload
                ))
            }
        }
    }
}

/// Database of known types.
pub(crate) struct TypeDatabase {
    by_rs_name: HashMap<TypeName, TypeDetails>,
    by_cppname: HashMap<String, String>,
}

lazy_static! {
    /// Database of known types.
    static ref KNOWN_TYPES: TypeDatabase = create_type_database();
}

fn create_type_database() -> TypeDatabase {
    let mut by_rs_name = HashMap::new();

    let mut do_insert =
        |td: TypeDetails| by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);

    do_insert(TypeDetails::new(
        "UniquePtr".into(),
        "std::unique_ptr".into(),
        true,
        PreludePolicy::IncludeTemplated,
        false,
    ));
    do_insert(TypeDetails::new(
        "CxxString".into(),
        "std::string".into(),
        false,
        PreludePolicy::IncludeNormal,
        false,
    ));
    do_insert(TypeDetails::new(
        "str".into(),
        "rust::Str".into(),
        true,
        PreludePolicy::IncludeNormal,
        true,
    ));
    do_insert(TypeDetails::new(
        "String".into(),
        "rust::String".into(),
        true,
        PreludePolicy::IncludeNormal,
        false,
    ));
    for (cpp_type, rust_type) in (3..7)
        .map(|x| 2i32.pow(x))
        .map(|x| {
            vec![
                (format!("uint{}_t", x), format!("u{}", x)),
                (format!("int{}_t", x), format!("i{}", x)),
            ]
        })
        .flatten()
    {
        do_insert(TypeDetails::new(
            rust_type,
            cpp_type,
            true,
            PreludePolicy::Exclude,
            false,
        ));
    }

    let mut by_cppname = HashMap::new();
    for td in by_rs_name.values() {
        by_cppname.insert(td.cpp_name.clone(), td.rs_name.clone());
    }

    TypeDatabase {
        by_rs_name,
        by_cppname,
    }
}

/// This is worked out basically using trial and error.
/// Excluding std* and rust* is obvious, but the other items...
/// in theory bindgen ought to be smart enough to work out that
/// they're not used and therefore not generate code for them.
/// But it doesm unless we blocklist them. This is obviously
/// a bit sensitive to the particular STL in use so one day
/// it would be good to dig into bindgen's behavior here - TODO.
const BINDGEN_BLOCKLIST: &[&str] = &["std.*", "__gnu.*", ".*mbstate_t.*", "rust.*"];

/// Prelude of C++ for squirting into bindgen. This configures
/// bindgen to output simpler types to replace some STL types
/// that bindgen just can't cope with. Although we then replace
/// those types with cxx types (e.g. UniquePtr), this intermediate
/// step is still necessary because bindgen can't otherwise
/// give us the templated types (e.g. when faced with the STL
/// unique_ptr, bindgen would normally give us std_unique_ptr
/// as opposed to std_unique_ptr<T>.)
pub(crate) fn get_prelude() -> String {
    itertools::join(
        KNOWN_TYPES
            .by_rs_name
            .values()
            .filter_map(|t| t.get_prelude_entry()),
        "\n",
    )
}

/// Types which are known to be safe (or unsafe) to hold and pass by
/// value in Rust.
pub(crate) fn get_pod_safe_types() -> Vec<(TypeName, bool)> {
    KNOWN_TYPES
        .by_rs_name
        .iter()
        .map(|(_, td)| {
            (
                TypeName::from_ident(&make_ident(&td.rs_name)),
                td.by_value_safe,
            )
        })
        .collect()
}

/// Get the list of types to give to bindgen to ask it _not_ to
/// generate code for.
pub(crate) fn get_initial_blocklist() -> Vec<String> {
    BINDGEN_BLOCKLIST.iter().map(|s| s.to_string()).collect()
}

/// Whether this TypePath should be treated as a value in C++
/// but a reference in Rust. This only applies to rust::Str
/// (C++ name) which is &str in Rust.
pub(crate) fn should_dereference_in_cpp(typ: &TypePath) -> bool {
    let tn = TypeName::from_cxx_type_path(typ);
    let td = KNOWN_TYPES.by_rs_name.get(&tn);
    if let Some(td) = td {
        td.de_referencicate
    } else {
        false
    }
}

/// Here we substitute any names which we know are Special from
/// our type database, e.g. std::unique_ptr -> UniquePtr.
/// The 'without_arguments' bit means we strip off and ignore
/// any PathArguments within this TypePath - callers should
/// put them back again if needs be.
pub(crate) fn replace_type_path_without_arguments(typ: TypePath) -> TypePath {
    let name = TypeName::from_cxx_type_path(&typ).to_cpp_name();
    match KNOWN_TYPES.by_cppname.get(&name) {
        Some(replacement_name) => {
            let id = make_ident(replacement_name);
            parse_quote! {
                #id
            }
        }
        None => typ,
    }
}

pub(crate) fn special_cpp_name(rs: &TypeName) -> Option<String> {
    KNOWN_TYPES
        .by_rs_name
        .get(rs)
        .map(|x| x.cpp_name.to_string())
}

fn make_ident(id: &str) -> Ident {
    Ident::new(id, Span::call_site())
}
<commit_msg>Support bool type.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::types::TypeName;
use indoc::indoc;
use lazy_static::lazy_static;
use proc_macro2::Span;
use std::collections::HashMap;
use syn::{parse_quote, Ident, TypePath};

/// Whether this type should be included in the 'prelude'
/// passed to bindgen, and if so, how.
#[derive(Debug)]
enum PreludePolicy {
    Exclude,
    IncludeNormal,
    IncludeTemplated,
}

/// Details about known special types, mostly primitives.
#[derive(Debug)]
struct TypeDetails {
    /// The name used by cxx (in Rust code) for this type.
    rs_name: String,
    /// C++ equivalent name for a Rust type.
    cpp_name: String,
    /// Whether this can be safely represented by value.
    by_value_safe: bool,
    /// Whether and how to include this in the prelude given to bindgen.
    prelude_policy: PreludePolicy,
    /// Whether this is a & on the Rust side but a value on the C++
    /// side. Only applies to &str.
    de_referencicate: bool,
}

impl TypeDetails {
    fn new(
        rs_name: String,
        cpp_name: String,
        by_value_safe: bool,
        prelude_policy: PreludePolicy,
        de_referencicate: bool,
    ) -> Self {
        TypeDetails {
            rs_name,
            cpp_name,
            by_value_safe,
            prelude_policy,
            de_referencicate,
        }
    }

    fn get_prelude_entry(&self) -> Option<String> {
        match self.prelude_policy {
            PreludePolicy::Exclude => None,
            PreludePolicy::IncludeNormal | PreludePolicy::IncludeTemplated => {
                let cxx_name = &self.rs_name;
                let (templating, payload) = match self.prelude_policy {
                    PreludePolicy::IncludeNormal => ("", "char* ptr"),
                    PreludePolicy::IncludeTemplated => ("template<typename T> ", "T* ptr"),
                    _ => unreachable!(),
                };
                Some(format!(
                    indoc! {"
                    /**
                    *

                    */
                    {}class {} {{
                        {};
                    }};

                    "},
                    self.cpp_name, templating, cxx_name, payload
                ))
            }
        }
    }
}

/// Database of known types.
pub(crate) struct TypeDatabase {
    by_rs_name: HashMap<TypeName, TypeDetails>,
    by_cppname: HashMap<String, String>,
}

lazy_static! {
    /// Database of known types.
    static ref KNOWN_TYPES: TypeDatabase = create_type_database();
}

fn create_type_database() -> TypeDatabase {
    let mut by_rs_name = HashMap::new();

    let mut do_insert =
        |td: TypeDetails| by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);

    do_insert(TypeDetails::new(
        "UniquePtr".into(),
        "std::unique_ptr".into(),
        true,
        PreludePolicy::IncludeTemplated,
        false,
    ));
    do_insert(TypeDetails::new(
        "CxxString".into(),
        "std::string".into(),
        false,
        PreludePolicy::IncludeNormal,
        false,
    ));
    do_insert(TypeDetails::new(
        "str".into(),
        "rust::Str".into(),
        true,
        PreludePolicy::IncludeNormal,
        true,
    ));
    do_insert(TypeDetails::new(
        "String".into(),
        "rust::String".into(),
        true,
        PreludePolicy::IncludeNormal,
        false,
    ));
    for (cpp_type, rust_type) in (3..7)
        .map(|x| 2i32.pow(x))
        .map(|x| {
            vec![
                (format!("uint{}_t", x), format!("u{}", x)),
                (format!("int{}_t", x), format!("i{}", x)),
            ]
        })
        .flatten()
    {
        do_insert(TypeDetails::new(
            rust_type,
            cpp_type,
            true,
            PreludePolicy::Exclude,
            false,
        ));
    }
    do_insert(TypeDetails::new(
        "bool".into(),
        "bool".into(),
        true,
        PreludePolicy::Exclude,
        false,
    ));

    let mut by_cppname = HashMap::new();
    for td in by_rs_name.values() {
        by_cppname.insert(td.cpp_name.clone(), td.rs_name.clone());
    }

    TypeDatabase {
        by_rs_name,
        by_cppname,
    }
}

/// This is worked out basically using trial and error.
/// Excluding std* and rust* is obvious, but the other items...
/// in theory bindgen ought to be smart enough to work out that
/// they're not used and therefore not generate code for them.
/// But it doesm unless we blocklist them. This is obviously
/// a bit sensitive to the particular STL in use so one day
/// it would be good to dig into bindgen's behavior here - TODO.
const BINDGEN_BLOCKLIST: &[&str] = &["std.*", "__gnu.*", ".*mbstate_t.*", "rust.*"];

/// Prelude of C++ for squirting into bindgen. This configures
/// bindgen to output simpler types to replace some STL types
/// that bindgen just can't cope with. Although we then replace
/// those types with cxx types (e.g. UniquePtr), this intermediate
/// step is still necessary because bindgen can't otherwise
/// give us the templated types (e.g. when faced with the STL
/// unique_ptr, bindgen would normally give us std_unique_ptr
/// as opposed to std_unique_ptr<T>.)
pub(crate) fn get_prelude() -> String {
    itertools::join(
        KNOWN_TYPES
            .by_rs_name
            .values()
            .filter_map(|t| t.get_prelude_entry()),
        "\n",
    )
}

/// Types which are known to be safe (or unsafe) to hold and pass by
/// value in Rust.
pub(crate) fn get_pod_safe_types() -> Vec<(TypeName, bool)> {
    KNOWN_TYPES
        .by_rs_name
        .iter()
        .map(|(_, td)| {
            (
                TypeName::from_ident(&make_ident(&td.rs_name)),
                td.by_value_safe,
            )
        })
        .collect()
}

/// Get the list of types to give to bindgen to ask it _not_ to
/// generate code for.
pub(crate) fn get_initial_blocklist() -> Vec<String> {
    BINDGEN_BLOCKLIST.iter().map(|s| s.to_string()).collect()
}

/// Whether this TypePath should be treated as a value in C++
/// but a reference in Rust. This only applies to rust::Str
/// (C++ name) which is &str in Rust.
pub(crate) fn should_dereference_in_cpp(typ: &TypePath) -> bool {
    let tn = TypeName::from_cxx_type_path(typ);
    let td = KNOWN_TYPES.by_rs_name.get(&tn);
    if let Some(td) = td {
        td.de_referencicate
    } else {
        false
    }
}

/// Here we substitute any names which we know are Special from
/// our type database, e.g. std::unique_ptr -> UniquePtr.
/// The 'without_arguments' bit means we strip off and ignore
/// any PathArguments within this TypePath - callers should
/// put them back again if needs be.
pub(crate) fn replace_type_path_without_arguments(typ: TypePath) -> TypePath {
    let name = TypeName::from_cxx_type_path(&typ).to_cpp_name();
    match KNOWN_TYPES.by_cppname.get(&name) {
        Some(replacement_name) => {
            let id = make_ident(replacement_name);
            parse_quote! {
                #id
            }
        }
        None => typ,
    }
}

pub(crate) fn special_cpp_name(rs: &TypeName) -> Option<String> {
    KNOWN_TYPES
        .by_rs_name
        .get(rs)
        .map(|x| x.cpp_name.to_string())
}

fn make_ident(id: &str) -> Ident {
    Ident::new(id, Span::call_site())
}
<|endoftext|>


<commit_before>//! Diesel is an ORM and query builder designed to reduce the boilerplate for database
//! interactions. [A getting started guide](http://diesel.rs/guides/getting-started/) can be
//! found on our website.
#![cfg_attr(feature = "unstable", feature(specialization))]

// Built-in Lints
#![deny(warnings, missing_debug_implementations, missing_copy_implementations)]

// Clippy lints
#![cfg_attr(feature = "clippy", allow(unstable_features))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file="../clippy.toml")))]
#![cfg_attr(feature = "clippy", allow(
    option_map_unwrap_or_else, option_map_unwrap_or,
    match_same_arms, type_complexity,
))]
#![cfg_attr(feature = "clippy", warn(
    option_unwrap_used, result_unwrap_used, print_stdout, wrong_pub_self_convention,
    mut_mut, non_ascii_literal, similar_names, unicode_not_nfc,
    enum_glob_use, if_not_else, items_after_statements, used_underscore_binding,
))]
#![cfg_attr(all(test, feature = "clippy"), allow(result_unwrap_used))]

extern crate byteorder;

#[macro_use]
mod macros;

#[cfg(test)]
#[macro_use]
extern crate cfg_if;

#[cfg(test)]
pub mod test_helpers;

pub mod associations;
pub mod backend;
pub mod connection;
#[macro_use]
pub mod expression;
#[doc(hidden)]
pub mod insertable;
pub mod query_builder;
#[macro_use]
pub mod types;

#[deprecated(since = "0.10.0", note = "use `insertable` instead")]
#[cfg(feature = "with-deprecated")]
pub use self::insertable as persistable;

#[cfg(feature = "mysql")]
pub mod mysql;
#[cfg(feature = "postgres")]
pub mod pg;
#[cfg(feature = "sqlite")]
pub mod sqlite;

pub mod migrations;
mod query_dsl;
pub mod query_source;
pub mod result;
pub mod row;

pub mod helper_types {
    //! Provide helper types for concisely writing the return type of functions.
    //! As with iterators, it is unfortunately difficult to return a partially
    //! constructed query without exposing the exact implementation of the
    //! function. Without higher kinded types, these various DSLs can't be
    //! combined into a single trait for boxing purposes.
    //!
    //! All types here are in the form `<FirstType as
    //! DslName<OtherTypes>>::Output`. So the return type of
    //! `users.filter(first_name.eq("John")).order(last_name.asc()).limit(10)` would
    //! be `Limit<Order<FindBy<users, first_name, &str>, Asc<last_name>>>`
    use super::query_dsl::*;
    use super::expression::helper_types::Eq;

    /// Represents the return type of `.select(selection)`
    pub type Select<Source, Selection> =
        <Source as SelectDsl<Selection>>::Output;

    /// Represents the return type of `.filter(predicate)`
    pub type Filter<Source, Predicate> =
        <Source as FilterDsl<Predicate>>::Output;

    /// Represents the return type of `.filter(lhs.eq(rhs))`
    pub type FindBy<Source, Column, Value> =
        Filter<Source, Eq<Column, Value>>;

    /// Represents the return type of `.find(pk)`
    pub type Find<Source, PK> = <Source as FindDsl<PK>>::Output;

    /// Represents the return type of `.order(ordering)`
    pub type Order<Source, Ordering> =
        <Source as OrderDsl<Ordering>>::Output;

    /// Represents the return type of `.limit()`
    pub type Limit<Source> = <Source as LimitDsl>::Output;

    /// Represents the return type of `.offset()`
    pub type Offset<Source> = <Source as OffsetDsl>::Output;

    use super::associations::HasTable;
    use super::query_builder::{UpdateStatement, IntoUpdateTarget, AsChangeset};
    /// Represents the return type of `update(lhs).set(rhs)`
    pub type Update<Target, Changes> = UpdateStatement<
        <Target as HasTable>::Table,
        <Target as IntoUpdateTarget>::WhereClause,
        <Changes as AsChangeset>::Changeset,
    >;
}

pub mod prelude {
    //! Re-exports important traits and types. Meant to be glob imported when using Diesel.
    pub use associations::GroupedBy;
    pub use connection::Connection;
    pub use expression::{Expression, SelectableExpression, AppearsOnTable, BoxableExpression};
    pub use expression::expression_methods::*;
    #[doc(inline)]
    pub use insertable::Insertable;
    pub use query_dsl::*;
    pub use query_source::{QuerySource, Queryable, Table, Column, JoinTo};
    pub use result::{QueryResult, ConnectionError, ConnectionResult, OptionalExtension};
}

pub use prelude::*;
#[doc(inline)]
pub use query_builder::functions::{insert, update, delete, select};
#[cfg(feature = "sqlite")]
pub use sqlite::query_builder::functions::*;
pub use result::Error::NotFound;
#[doc(inline)]
pub use types::structs::data_types;
<commit_msg>Place `Identifiable` in prelude<commit_after>//! Diesel is an ORM and query builder designed to reduce the boilerplate for database
//! interactions. [A getting started guide](http://diesel.rs/guides/getting-started/) can be
//! found on our website.
#![cfg_attr(feature = "unstable", feature(specialization))]

// Built-in Lints
#![deny(warnings, missing_debug_implementations, missing_copy_implementations)]

// Clippy lints
#![cfg_attr(feature = "clippy", allow(unstable_features))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file="../clippy.toml")))]
#![cfg_attr(feature = "clippy", allow(
    option_map_unwrap_or_else, option_map_unwrap_or,
    match_same_arms, type_complexity,
))]
#![cfg_attr(feature = "clippy", warn(
    option_unwrap_used, result_unwrap_used, print_stdout, wrong_pub_self_convention,
    mut_mut, non_ascii_literal, similar_names, unicode_not_nfc,
    enum_glob_use, if_not_else, items_after_statements, used_underscore_binding,
))]
#![cfg_attr(all(test, feature = "clippy"), allow(result_unwrap_used))]

extern crate byteorder;

#[macro_use]
mod macros;

#[cfg(test)]
#[macro_use]
extern crate cfg_if;

#[cfg(test)]
pub mod test_helpers;

pub mod associations;
pub mod backend;
pub mod connection;
#[macro_use]
pub mod expression;
#[doc(hidden)]
pub mod insertable;
pub mod query_builder;
#[macro_use]
pub mod types;

#[deprecated(since = "0.10.0", note = "use `insertable` instead")]
#[cfg(feature = "with-deprecated")]
pub use self::insertable as persistable;

#[cfg(feature = "mysql")]
pub mod mysql;
#[cfg(feature = "postgres")]
pub mod pg;
#[cfg(feature = "sqlite")]
pub mod sqlite;

pub mod migrations;
mod query_dsl;
pub mod query_source;
pub mod result;
pub mod row;

pub mod helper_types {
    //! Provide helper types for concisely writing the return type of functions.
    //! As with iterators, it is unfortunately difficult to return a partially
    //! constructed query without exposing the exact implementation of the
    //! function. Without higher kinded types, these various DSLs can't be
    //! combined into a single trait for boxing purposes.
    //!
    //! All types here are in the form `<FirstType as
    //! DslName<OtherTypes>>::Output`. So the return type of
    //! `users.filter(first_name.eq("John")).order(last_name.asc()).limit(10)` would
    //! be `Limit<Order<FindBy<users, first_name, &str>, Asc<last_name>>>`
    use super::query_dsl::*;
    use super::expression::helper_types::Eq;

    /// Represents the return type of `.select(selection)`
    pub type Select<Source, Selection> =
        <Source as SelectDsl<Selection>>::Output;

    /// Represents the return type of `.filter(predicate)`
    pub type Filter<Source, Predicate> =
        <Source as FilterDsl<Predicate>>::Output;

    /// Represents the return type of `.filter(lhs.eq(rhs))`
    pub type FindBy<Source, Column, Value> =
        Filter<Source, Eq<Column, Value>>;

    /// Represents the return type of `.find(pk)`
    pub type Find<Source, PK> = <Source as FindDsl<PK>>::Output;

    /// Represents the return type of `.order(ordering)`
    pub type Order<Source, Ordering> =
        <Source as OrderDsl<Ordering>>::Output;

    /// Represents the return type of `.limit()`
    pub type Limit<Source> = <Source as LimitDsl>::Output;

    /// Represents the return type of `.offset()`
    pub type Offset<Source> = <Source as OffsetDsl>::Output;

    use super::associations::HasTable;
    use super::query_builder::{UpdateStatement, IntoUpdateTarget, AsChangeset};
    /// Represents the return type of `update(lhs).set(rhs)`
    pub type Update<Target, Changes> = UpdateStatement<
        <Target as HasTable>::Table,
        <Target as IntoUpdateTarget>::WhereClause,
        <Changes as AsChangeset>::Changeset,
    >;
}

pub mod prelude {
    //! Re-exports important traits and types. Meant to be glob imported when using Diesel.
    pub use associations::{GroupedBy, Identifiable};
    pub use connection::Connection;
    pub use expression::{Expression, SelectableExpression, AppearsOnTable, BoxableExpression};
    pub use expression::expression_methods::*;
    #[doc(inline)]
    pub use insertable::Insertable;
    pub use query_dsl::*;
    pub use query_source::{QuerySource, Queryable, Table, Column, JoinTo};
    pub use result::{QueryResult, ConnectionError, ConnectionResult, OptionalExtension};
}

pub use prelude::*;
#[doc(inline)]
pub use query_builder::functions::{insert, update, delete, select};
#[cfg(feature = "sqlite")]
pub use sqlite::query_builder::functions::*;
pub use result::Error::NotFound;
#[doc(inline)]
pub use types::structs::data_types;
<|endoftext|>


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

#![feature(mpsc_recv_timeout)]
#![feature(test)]
#![feature(box_syntax)]
#![feature(integer_atomics)]
#![feature(btree_range, collections_bound)]
#![cfg_attr(not(feature = "cargo-clippy"), allow(unknown_lints))]

extern crate clap;
extern crate futures;
extern crate grpcio as grpc;
extern crate kvproto;
#[macro_use]
extern crate log;
#[macro_use(slog_o, slog_kv)]
extern crate slog;
extern crate protobuf;
extern crate raft;
extern crate rand;
extern crate rocksdb;
extern crate slog_async;
extern crate slog_scope;
extern crate slog_stdlog;
extern crate slog_term;
extern crate tempdir;
extern crate test;
extern crate time;
#[macro_use]
extern crate tikv;
extern crate tokio_timer;

#[allow(dead_code)]
#[path = "../../tests/raftstore/cluster.rs"]
mod cluster;
#[path = "../../tests/raftstore/node.rs"]
mod node;
#[allow(dead_code)]
#[path = "../../tests/raftstore/pd.rs"]
mod pd;
#[path = "../../tests/raftstore/server.rs"]
mod server;
#[allow(dead_code)]
#[path = "../../tests/util/mod.rs"]
mod test_util;
#[allow(dead_code)]
#[path = "../../tests/raftstore/transport_simulate.rs"]
mod transport_simulate;
#[allow(dead_code)]
#[path = "../../tests/raftstore/util.rs"]
mod util;

use clap::{App, Arg, ArgGroup};
use test::BenchSamples;

/// shortcut to bench a function.
macro_rules! bench {
    ($name:expr, $block:expr) => {{
        use std::sync::mpsc::channel;
        use test::{self, bench};
        let desc = test::TestDesc {
            name: test::TestName::DynTestName($name.into()),
            ignore: false,
            should_panic: test::ShouldPanic::No,
            allow_fail: false,
        };
        let (tx, rx) = channel();
        bench::benchmark(desc, tx, false, |b| b.iter($block));
        let (_desc, result, _stdout) = rx.recv().unwrap();
        match result {
            test::TestResult::TrBench(samples) => samples,
            _ => unreachable!(),
        }
    }};
}

/// Same as print, but will flush automatically.
macro_rules! printf {
    ($($arg:tt)*) => ({
        use std::io::{self, Write};
        print!($($arg)*);
        io::stdout().flush().unwrap();
    });
}

#[allow(dead_code)]
mod utils;

mod mvcc;
mod raftstore;

fn print_result(smp: BenchSamples) {
    println!("{}", test::fmt_bench_samples(&smp));
}

fn main() {
    if let Err(e) = tikv::util::config::check_max_open_fds(4096) {
        panic!(
            "To run bench, please make sure the maximum number of open file descriptors not \
             less than 4096: {:?}",
            e
        );
    }

    let available_benches = ["raftstore", "mvcc"];

    let matches = App::new("TiKV Benchmark")
        .args(
            &available_benches
                .iter()
                .map(|name| Arg::with_name(name))
                .collect::<Vec<_>>(),
        )
        .group(
            ArgGroup::with_name("benches")
                .args(&available_benches)
                .multiple(true),
        )
        .get_matches();

    let benches: Vec<_> = if let Some(args) = matches.values_of("benches") {
        args.collect()
    } else {
        available_benches.to_vec()
    };

    println!("Begin to run: {}", benches.join(", "));

    for item in benches {
        match item {
            "raftstore" => raftstore::bench_raftstore(),
            "mvcc" => mvcc::bench_engine(),
            _ => eprintln!("error: Unknown bench item {}", item),
        }
    }
}
<commit_msg>Remove useless unknown_lints (#3282)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(mpsc_recv_timeout)]
#![feature(test)]
#![feature(box_syntax)]
#![feature(integer_atomics)]
#![feature(btree_range, collections_bound)]

extern crate clap;
extern crate futures;
extern crate grpcio as grpc;
extern crate kvproto;
#[macro_use]
extern crate log;
#[macro_use(slog_o, slog_kv)]
extern crate slog;
extern crate protobuf;
extern crate raft;
extern crate rand;
extern crate rocksdb;
extern crate slog_async;
extern crate slog_scope;
extern crate slog_stdlog;
extern crate slog_term;
extern crate tempdir;
extern crate test;
extern crate time;
#[macro_use]
extern crate tikv;
extern crate tokio_timer;

#[allow(dead_code)]
#[path = "../../tests/raftstore/cluster.rs"]
mod cluster;
#[path = "../../tests/raftstore/node.rs"]
mod node;
#[allow(dead_code)]
#[path = "../../tests/raftstore/pd.rs"]
mod pd;
#[path = "../../tests/raftstore/server.rs"]
mod server;
#[allow(dead_code)]
#[path = "../../tests/util/mod.rs"]
mod test_util;
#[allow(dead_code)]
#[path = "../../tests/raftstore/transport_simulate.rs"]
mod transport_simulate;
#[allow(dead_code)]
#[path = "../../tests/raftstore/util.rs"]
mod util;

use clap::{App, Arg, ArgGroup};
use test::BenchSamples;

/// shortcut to bench a function.
macro_rules! bench {
    ($name:expr, $block:expr) => {{
        use std::sync::mpsc::channel;
        use test::{self, bench};
        let desc = test::TestDesc {
            name: test::TestName::DynTestName($name.into()),
            ignore: false,
            should_panic: test::ShouldPanic::No,
            allow_fail: false,
        };
        let (tx, rx) = channel();
        bench::benchmark(desc, tx, false, |b| b.iter($block));
        let (_desc, result, _stdout) = rx.recv().unwrap();
        match result {
            test::TestResult::TrBench(samples) => samples,
            _ => unreachable!(),
        }
    }};
}

/// Same as print, but will flush automatically.
macro_rules! printf {
    ($($arg:tt)*) => ({
        use std::io::{self, Write};
        print!($($arg)*);
        io::stdout().flush().unwrap();
    });
}

#[allow(dead_code)]
mod utils;

mod mvcc;
mod raftstore;

fn print_result(smp: BenchSamples) {
    println!("{}", test::fmt_bench_samples(&smp));
}

fn main() {
    if let Err(e) = tikv::util::config::check_max_open_fds(4096) {
        panic!(
            "To run bench, please make sure the maximum number of open file descriptors not \
             less than 4096: {:?}",
            e
        );
    }

    let available_benches = ["raftstore", "mvcc"];

    let matches = App::new("TiKV Benchmark")
        .args(
            &available_benches
                .iter()
                .map(|name| Arg::with_name(name))
                .collect::<Vec<_>>(),
        )
        .group(
            ArgGroup::with_name("benches")
                .args(&available_benches)
                .multiple(true),
        )
        .get_matches();

    let benches: Vec<_> = if let Some(args) = matches.values_of("benches") {
        args.collect()
    } else {
        available_benches.to_vec()
    };

    println!("Begin to run: {}", benches.join(", "));

    for item in benches {
        match item {
            "raftstore" => raftstore::bench_raftstore(),
            "mvcc" => mvcc::bench_engine(),
            _ => eprintln!("error: Unknown bench item {}", item),
        }
    }
}
<|endoftext|>