<commit_before>use crate::connection_string::*;

pub struct ConnectionStringBuilder<'a>(ConnectionString<'a>);

impl<'a> ConnectionStringBuilder<'a> {
    pub fn new() -> Self {
        Self(ConnectionString::default())
    }

    pub fn build(&self) -> String {
        let mut kv_pairs = Vec::new();

        if let Some(account_name) = self.0.account_name {
            kv_pairs.push(format!("{}={}", ACCOUNT_NAME_KEY_NAME, account_name));
        }
        if let Some(account_key) = self.0.account_key {
            kv_pairs.push(format!("{}={}", ACCOUNT_KEY_KEY_NAME, account_key));
        }
        if let Some(sas) = self.0.sas {
            kv_pairs.push(format!("{}={}", SAS_KEY_NAME, sas));
        }
        if let Some(use_development_storage) = self.0.use_development_storage {
            kv_pairs.push(format!(
                "{}={}",
                USE_DEVELOPMENT_STORAGE_KEY_NAME, use_development_storage
            ));
        }
        if let Some(development_storage_proxy_uri) = self.0.development_storage_proxy_uri {
            kv_pairs.push(format!(
                "{}={}",
                DEVELOPMENT_STORAGE_PROXY_URI_KEY_NAME, development_storage_proxy_uri
            ));
        }
        if let Some(endpoint_suffix) = self.0.endpoint_suffix {
            kv_pairs.push(format!(
                "{}={}",
                ENDPOINT_SUFFIX_KEY_NAME,
                endpoint_suffix.to_string()
            ));
        }
        if let Some(default_endpoints_protocol) = self.0.default_endpoints_protocol.as_ref() {
            kv_pairs.push(format!(
                "{}={}",
                DEFAULT_ENDPOINTS_PROTOCOL_KEY_NAME,
                default_endpoints_protocol.to_string()
            ));
        }
        if let Some(blob_endpoint) = self.0.blob_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                BLOB_ENDPOINT_KEY_NAME,
                blob_endpoint.to_string()
            ));
        }
        if let Some(blob_secondary_endpoint) = self.0.blob_secondary_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                BLOB_SECONDARY_ENDPOINT_KEY_NAME,
                blob_secondary_endpoint.to_string()
            ));
        }
        if let Some(table_endpoint) = self.0.table_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                TABLE_ENDPOINT_KEY_NAME,
                table_endpoint.to_string()
            ));
        }
        if let Some(table_secondary_endpoint) = self.0.table_secondary_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                TABLE_SECONDARY_ENDPOINT_KEY_NAME,
                table_secondary_endpoint.to_string()
            ));
        }
        if let Some(queue_endpoint) = self.0.queue_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                QUEUE_ENDPOINT_KEY_NAME,
                queue_endpoint.to_string()
            ));
        }
        if let Some(queue_secondary_endpoint) = self.0.queue_secondary_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                QUEUE_SECONDARY_ENDPOINT_KEY_NAME,
                queue_secondary_endpoint.to_string()
            ));
        }
        if let Some(file_endpoint) = self.0.file_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                FILE_ENDPOINT_KEY_NAME,
                file_endpoint.to_string()
            ));
        }
        if let Some(file_secondary_endpoint) = self.0.file_secondary_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                FILE_SECONDARY_ENDPOINT_KEY_NAME,
                file_secondary_endpoint.to_string()
            ));
        }

        kv_pairs.join(";")
    }

    pub fn with_account_name(&'a mut self, account_name: &'a str) -> &'a mut Self {
        self.0.account_name = Some(account_name);
        self
    }

    pub fn with_account_key(&'a mut self, account_key: &'a str) -> &'a mut Self {
        self.0.account_key = Some(account_key);
        self
    }

    pub fn with_sas(&'a mut self, sas: &'a str) -> &'a mut Self {
        self.0.sas = Some(sas);
        self
    }

    pub fn with_endpoint_suffix(&'a mut self, endpoint_suffix: &'a str) -> &'a mut Self {
        self.0.endpoint_suffix = Some(endpoint_suffix);
        self
    }

    pub fn with_default_endpoints_protocol(
        &'a mut self,
        default_endpoints_protocol: EndpointProtocol,
    ) -> &'a mut Self {
        self.0.default_endpoints_protocol = Some(default_endpoints_protocol);
        self
    }

    pub fn with_use_development_storage(
        &'a mut self,
        use_development_storage: bool,
    ) -> &'a mut Self {
        self.0.use_development_storage = Some(use_development_storage);
        self
    }

    pub fn with_development_storage_proxy_uri(
        &'a mut self,
        development_storage_proxy_uri: &'a str,
    ) -> &'a mut Self {
        self.0.development_storage_proxy_uri = Some(development_storage_proxy_uri);
        self
    }

    pub fn with_blob_endpoint(&'a mut self, blob_endpoint: &'a str) -> &'a mut Self {
        self.0.blob_endpoint = Some(blob_endpoint);
        self
    }

    pub fn with_blob_secondary_endpoint(
        &'a mut self,
        blob_secondary_endpoint: &'a str,
    ) -> &'a mut Self {
        self.0.blob_secondary_endpoint = Some(blob_secondary_endpoint);
        self
    }

    pub fn with_table_endpoint(&'a mut self, table_endpoint: &'a str) -> &'a mut Self {
        self.0.table_endpoint = Some(table_endpoint);
        self
    }

    pub fn with_table_secondary_endpoint(
        &'a mut self,
        table_secondary_endpoint: &'a str,
    ) -> &'a mut Self {
        self.0.table_secondary_endpoint = Some(table_secondary_endpoint);
        self
    }

    pub fn with_queue_endpoint(&'a mut self, queue_endpoint: &'a str) -> &'a mut Self {
        self.0.queue_endpoint = Some(queue_endpoint);
        self
    }

    pub fn with_queue_secondary_endpoint(
        &'a mut self,
        queue_secondary_endpoint: &'a str,
    ) -> &'a mut Self {
        self.0.queue_secondary_endpoint = Some(queue_secondary_endpoint);
        self
    }

    pub fn with_file_endpoint(&'a mut self, file_endpoint: &'a str) -> &'a mut Self {
        self.0.file_endpoint = Some(file_endpoint);
        self
    }

    pub fn with_file_secondary_endpoint(
        &'a mut self,
        file_secondary_endpoint: &'a str,
    ) -> &'a mut Self {
        self.0.file_secondary_endpoint = Some(file_secondary_endpoint);
        self
    }
}

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

    #[test]
    fn it_builds_generic_connection_strings() {
        assert_eq!(ConnectionStringBuilder::new().build(), "");
        assert_eq!(
            ConnectionStringBuilder::new()
                .with_account_name("a")
                .with_account_key("b")
                .build(),
            "AccountName=a;AccountKey=b"
        );
        assert_eq!(
            ConnectionStringBuilder::new()
                .with_account_name("a")
                .with_sas("b")
                .with_default_endpoints_protocol(EndpointProtocol::Https)
                .with_blob_endpoint("c")
                .build(),
            "AccountName=a;SharedAccessSignature=b;DefaultEndpointsProtocol=https;BlobEndpoint=c"
        );
    }

    #[test]
    fn it_builds_endpoints_with_development_storage() {
        assert_eq!(
            ConnectionStringBuilder::new()
                .with_use_development_storage(true)
                .with_development_storage_proxy_uri("a")
                .build(),
            "UseDevelopmentStorage=true;DevelopmentStorageProxyUri=a"
        );
        assert_eq!(
            ConnectionStringBuilder::new()
                .with_use_development_storage(false)
                .build(),
            "UseDevelopmentStorage=false"
        );
    }

    #[test]
    fn it_builds_all_endpoints() {
        assert_eq!(
            ConnectionStringBuilder::new()
                .with_blob_endpoint("b1")
                .with_blob_secondary_endpoint("b2")
                .with_table_endpoint("t1")
                .with_table_secondary_endpoint("t2")
                .with_queue_endpoint("q1")
                .with_queue_secondary_endpoint("q2")
                .with_file_endpoint("f1")
                .with_file_secondary_endpoint("f2")
                .build(),
            "BlobEndpoint=b1;BlobSecondaryEndpoint=b2;TableEndpoint=t1;TableSecondaryEndpoint=t2;QueueEndpoint=q1;QueueSecondaryEndpoint=q2;FileEndpoint=f1;FileSecondaryEndpoint=f2"
        );
    }
}
<commit_msg>Remove redundant `to_string` calls<commit_after>use crate::connection_string::*;

pub struct ConnectionStringBuilder<'a>(ConnectionString<'a>);

impl<'a> ConnectionStringBuilder<'a> {
    pub fn new() -> Self {
        Self(ConnectionString::default())
    }

    pub fn build(&self) -> String {
        let mut kv_pairs = Vec::new();

        if let Some(account_name) = self.0.account_name {
            kv_pairs.push(format!("{}={}", ACCOUNT_NAME_KEY_NAME, account_name));
        }
        if let Some(account_key) = self.0.account_key {
            kv_pairs.push(format!("{}={}", ACCOUNT_KEY_KEY_NAME, account_key));
        }
        if let Some(sas) = self.0.sas {
            kv_pairs.push(format!("{}={}", SAS_KEY_NAME, sas));
        }
        if let Some(use_development_storage) = self.0.use_development_storage {
            kv_pairs.push(format!(
                "{}={}",
                USE_DEVELOPMENT_STORAGE_KEY_NAME, use_development_storage
            ));
        }
        if let Some(development_storage_proxy_uri) = self.0.development_storage_proxy_uri {
            kv_pairs.push(format!(
                "{}={}",
                DEVELOPMENT_STORAGE_PROXY_URI_KEY_NAME, development_storage_proxy_uri
            ));
        }
        if let Some(endpoint_suffix) = self.0.endpoint_suffix {
            kv_pairs.push(format!(
                "{}={}",
                ENDPOINT_SUFFIX_KEY_NAME,
                endpoint_suffix
            ));
        }
        if let Some(default_endpoints_protocol) = self.0.default_endpoints_protocol.as_ref() {
            kv_pairs.push(format!(
                "{}={}",
                DEFAULT_ENDPOINTS_PROTOCOL_KEY_NAME,
                default_endpoints_protocol
            ));
        }
        if let Some(blob_endpoint) = self.0.blob_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                BLOB_ENDPOINT_KEY_NAME,
                blob_endpoint
            ));
        }
        if let Some(blob_secondary_endpoint) = self.0.blob_secondary_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                BLOB_SECONDARY_ENDPOINT_KEY_NAME,
                blob_secondary_endpoint
            ));
        }
        if let Some(table_endpoint) = self.0.table_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                TABLE_ENDPOINT_KEY_NAME,
                table_endpoint
            ));
        }
        if let Some(table_secondary_endpoint) = self.0.table_secondary_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                TABLE_SECONDARY_ENDPOINT_KEY_NAME,
                table_secondary_endpoint
            ));
        }
        if let Some(queue_endpoint) = self.0.queue_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                QUEUE_ENDPOINT_KEY_NAME,
                queue_endpoint
            ));
        }
        if let Some(queue_secondary_endpoint) = self.0.queue_secondary_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                QUEUE_SECONDARY_ENDPOINT_KEY_NAME,
                queue_secondary_endpoint
            ));
        }
        if let Some(file_endpoint) = self.0.file_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                FILE_ENDPOINT_KEY_NAME,
                file_endpoint
            ));
        }
        if let Some(file_secondary_endpoint) = self.0.file_secondary_endpoint {
            kv_pairs.push(format!(
                "{}={}",
                FILE_SECONDARY_ENDPOINT_KEY_NAME,
                file_secondary_endpoint
            ));
        }

        kv_pairs.join(";")
    }

    pub fn with_account_name(&'a mut self, account_name: &'a str) -> &'a mut Self {
        self.0.account_name = Some(account_name);
        self
    }

    pub fn with_account_key(&'a mut self, account_key: &'a str) -> &'a mut Self {
        self.0.account_key = Some(account_key);
        self
    }

    pub fn with_sas(&'a mut self, sas: &'a str) -> &'a mut Self {
        self.0.sas = Some(sas);
        self
    }

    pub fn with_endpoint_suffix(&'a mut self, endpoint_suffix: &'a str) -> &'a mut Self {
        self.0.endpoint_suffix = Some(endpoint_suffix);
        self
    }

    pub fn with_default_endpoints_protocol(
        &'a mut self,
        default_endpoints_protocol: EndpointProtocol,
    ) -> &'a mut Self {
        self.0.default_endpoints_protocol = Some(default_endpoints_protocol);
        self
    }

    pub fn with_use_development_storage(
        &'a mut self,
        use_development_storage: bool,
    ) -> &'a mut Self {
        self.0.use_development_storage = Some(use_development_storage);
        self
    }

    pub fn with_development_storage_proxy_uri(
        &'a mut self,
        development_storage_proxy_uri: &'a str,
    ) -> &'a mut Self {
        self.0.development_storage_proxy_uri = Some(development_storage_proxy_uri);
        self
    }

    pub fn with_blob_endpoint(&'a mut self, blob_endpoint: &'a str) -> &'a mut Self {
        self.0.blob_endpoint = Some(blob_endpoint);
        self
    }

    pub fn with_blob_secondary_endpoint(
        &'a mut self,
        blob_secondary_endpoint: &'a str,
    ) -> &'a mut Self {
        self.0.blob_secondary_endpoint = Some(blob_secondary_endpoint);
        self
    }

    pub fn with_table_endpoint(&'a mut self, table_endpoint: &'a str) -> &'a mut Self {
        self.0.table_endpoint = Some(table_endpoint);
        self
    }

    pub fn with_table_secondary_endpoint(
        &'a mut self,
        table_secondary_endpoint: &'a str,
    ) -> &'a mut Self {
        self.0.table_secondary_endpoint = Some(table_secondary_endpoint);
        self
    }

    pub fn with_queue_endpoint(&'a mut self, queue_endpoint: &'a str) -> &'a mut Self {
        self.0.queue_endpoint = Some(queue_endpoint);
        self
    }

    pub fn with_queue_secondary_endpoint(
        &'a mut self,
        queue_secondary_endpoint: &'a str,
    ) -> &'a mut Self {
        self.0.queue_secondary_endpoint = Some(queue_secondary_endpoint);
        self
    }

    pub fn with_file_endpoint(&'a mut self, file_endpoint: &'a str) -> &'a mut Self {
        self.0.file_endpoint = Some(file_endpoint);
        self
    }

    pub fn with_file_secondary_endpoint(
        &'a mut self,
        file_secondary_endpoint: &'a str,
    ) -> &'a mut Self {
        self.0.file_secondary_endpoint = Some(file_secondary_endpoint);
        self
    }
}

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

    #[test]
    fn it_builds_generic_connection_strings() {
        assert_eq!(ConnectionStringBuilder::new().build(), "");
        assert_eq!(
            ConnectionStringBuilder::new()
                .with_account_name("a")
                .with_account_key("b")
                .build(),
            "AccountName=a;AccountKey=b"
        );
        assert_eq!(
            ConnectionStringBuilder::new()
                .with_account_name("a")
                .with_sas("b")
                .with_default_endpoints_protocol(EndpointProtocol::Https)
                .with_blob_endpoint("c")
                .build(),
            "AccountName=a;SharedAccessSignature=b;DefaultEndpointsProtocol=https;BlobEndpoint=c"
        );
    }

    #[test]
    fn it_builds_endpoints_with_development_storage() {
        assert_eq!(
            ConnectionStringBuilder::new()
                .with_use_development_storage(true)
                .with_development_storage_proxy_uri("a")
                .build(),
            "UseDevelopmentStorage=true;DevelopmentStorageProxyUri=a"
        );
        assert_eq!(
            ConnectionStringBuilder::new()
                .with_use_development_storage(false)
                .build(),
            "UseDevelopmentStorage=false"
        );
    }

    #[test]
    fn it_builds_all_endpoints() {
        assert_eq!(
            ConnectionStringBuilder::new()
                .with_blob_endpoint("b1")
                .with_blob_secondary_endpoint("b2")
                .with_table_endpoint("t1")
                .with_table_secondary_endpoint("t2")
                .with_queue_endpoint("q1")
                .with_queue_secondary_endpoint("q2")
                .with_file_endpoint("f1")
                .with_file_secondary_endpoint("f2")
                .build(),
            "BlobEndpoint=b1;BlobSecondaryEndpoint=b2;TableEndpoint=t1;TableSecondaryEndpoint=t2;QueueEndpoint=q1;QueueSecondaryEndpoint=q2;FileEndpoint=f1;FileSecondaryEndpoint=f2"
        );
    }
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use super::filespec::SBFileSpec;
use super::listener::SBListener;
use super::lldb_pid_t;
use std::ffi::CString;
use sys;

/// Configuration for attaching to a process.
///
/// See [`SBTarget::attach`].
///
/// [`SBTarget::attach`]: struct.SBTarget.html#method.attach
#[derive(Debug)]
pub struct SBAttachInfo {
    /// The underlying raw `SBAttachInfoRef`.
    pub raw: sys::SBAttachInfoRef,
}

impl SBAttachInfo {
    /// Construct a new `SBAttachInfo`.
    pub fn new() -> SBAttachInfo {
        SBAttachInfo::from(unsafe { sys::CreateSBAttachInfo() })
    }

    /// Construct a new `SBAttachInfo` for a given process ID (pid).
    pub fn new_with_pid(pid: lldb_pid_t) -> SBAttachInfo {
        SBAttachInfo::from(unsafe { sys::CreateSBAttachInfo2(pid) })
    }

    /// Attach to a process by name.
    ///
    /// Future calls to `SBTarget::attach(...)` will be synchronous or
    /// asynchronous depending on the `async` argument.
    ///
    /// * `path`: A full or partial name for the process to attach to.
    /// * `wait_for`: If `false`, attach to an existing process whose name
    ///   matches. If `true`, then wait for the next process whose name
    ///   matches.
    /// * `async`: If `false`, then the `SBTarget::attach` call will be
    ///   synchronous with no way to cancel the attach while it is in
    ///   progress. If `true`, then the `SBTarget::attach` call will return
    ///   immediately and clients are expected to wait for a process
    ///   `eStateStopped` event if a suitable process is eventually found.
    ///   If the client wants to cancel the event, `SBProcess::stop` can be
    ///   called and an `eStateExited` process event will be delivered.
    pub fn new_with_path(path: &str, wait_for: bool, async: bool) -> SBAttachInfo {
        let p = CString::new(path).unwrap();
        SBAttachInfo::from(unsafe { sys::CreateSBAttachInfo4(p.as_ptr(), wait_for, async) })
    }

    #[allow(missing_docs)]
    pub fn process_id(&self) -> lldb_pid_t {
        unsafe { sys::SBAttachInfoGetProcessID(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn set_process_id(&self, pid: lldb_pid_t) {
        unsafe { sys::SBAttachInfoSetProcessID(self.raw, pid) };
    }

    #[allow(missing_docs)]
    pub fn set_executable_path(&self, path: &str) {
        let p = CString::new(path).unwrap();
        unsafe { sys::SBAttachInfoSetExecutable(self.raw, p.as_ptr()) }
    }

    #[allow(missing_docs)]
    pub fn set_executable_filespec(&self, exe_file: SBFileSpec) {
        unsafe { sys::SBAttachInfoSetExecutable2(self.raw, exe_file.raw) }
    }

    #[allow(missing_docs)]
    pub fn ignore_existing(&self) -> bool {
        unsafe { sys::SBAttachInfoGetIgnoreExisting(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn set_ignore_existing(&self, b: bool) {
        unsafe { sys::SBAttachInfoSetIgnoreExisting(self.raw, b) }
    }

    #[allow(missing_docs)]
    pub fn resume_count(&self) -> u32 {
        unsafe { sys::SBAttachInfoGetResumeCount(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn set_resume_count(&self, c: u32) {
        unsafe { sys::SBAttachInfoSetResumeCount(self.raw, c) }
    }

    /// Get the listener that will be used to receive process events.
    ///
    /// If no listener has been set via a call to
    /// `SBAttachInfo::set_listener()`, then an invalid `SBListener` will be
    /// returned (`SBListener::is_valid()` will return `false`). If a listener
    /// has been set, then the valid listener object will be returned.
    pub fn listener(&self) -> SBListener {
        SBListener::from(unsafe { sys::SBAttachInfoGetListener(self.raw) })
    }

    /// Set the listener that will be used to receive process events.
    ///
    /// By default the [`SBDebugger`], which has a listener,
    /// that the [`SBTarget`] belongs to will listen for the
    /// process events. Calling this function allows a different
    /// listener to be used to listen for process events.
    ///
    /// [`SBDebugger`]: struct.SBDebugger.html
    /// [`SBTarget`]: struct.SBTarget.html
    pub fn set_listener(&self, listener: SBListener) {
        unsafe { sys::SBAttachInfoSetListener(self.raw, listener.raw) };
    }
}

impl Clone for SBAttachInfo {
    fn clone(&self) -> SBAttachInfo {
        SBAttachInfo {
            raw: unsafe { sys::CloneSBAttachInfo(self.raw) },
        }
    }
}

impl Default for SBAttachInfo {
    fn default() -> SBAttachInfo {
        SBAttachInfo::new()
    }
}

impl Drop for SBAttachInfo {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBAttachInfo(self.raw) };
    }
}

impl From<sys::SBAttachInfoRef> for SBAttachInfo {
    fn from(raw: sys::SBAttachInfoRef) -> SBAttachInfo {
        SBAttachInfo { raw }
    }
}

unsafe impl Send for SBAttachInfo {}
unsafe impl Sync for SBAttachInfo {}
<commit_msg>SBAttachInfo: Add a bunch of missing methods.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use super::filespec::SBFileSpec;
use super::listener::SBListener;
use super::lldb_pid_t;
use std::ffi::{CStr, CString};
use sys;

/// Configuration for attaching to a process.
///
/// See [`SBTarget::attach()`].
///
/// [`SBTarget::attach()`]: crate::SBTarget::attach()
#[derive(Debug)]
pub struct SBAttachInfo {
    /// The underlying raw `SBAttachInfoRef`.
    pub raw: sys::SBAttachInfoRef,
}

impl SBAttachInfo {
    /// Construct a new `SBAttachInfo`.
    pub fn new() -> SBAttachInfo {
        SBAttachInfo::from(unsafe { sys::CreateSBAttachInfo() })
    }

    /// Construct a new `SBAttachInfo` for a given process ID (pid).
    pub fn new_with_pid(pid: lldb_pid_t) -> SBAttachInfo {
        SBAttachInfo::from(unsafe { sys::CreateSBAttachInfo2(pid) })
    }

    /// Attach to a process by name.
    ///
    /// Future calls to `SBTarget::attach(...)` will be synchronous or
    /// asynchronous depending on the `async` argument.
    ///
    /// * `path`: A full or partial name for the process to attach to.
    /// * `wait_for`: If `false`, attach to an existing process whose name
    ///   matches. If `true`, then wait for the next process whose name
    ///   matches.
    /// * `async`: If `false`, then the `SBTarget::attach` call will be
    ///   synchronous with no way to cancel the attach while it is in
    ///   progress. If `true`, then the `SBTarget::attach` call will return
    ///   immediately and clients are expected to wait for a process
    ///   `eStateStopped` event if a suitable process is eventually found.
    ///   If the client wants to cancel the event, `SBProcess::stop` can be
    ///   called and an `eStateExited` process event will be delivered.
    pub fn new_with_path(path: &str, wait_for: bool, async: bool) -> SBAttachInfo {
        let p = CString::new(path).unwrap();
        SBAttachInfo::from(unsafe { sys::CreateSBAttachInfo4(p.as_ptr(), wait_for, async) })
    }

    #[allow(missing_docs)]
    pub fn process_id(&self) -> lldb_pid_t {
        unsafe { sys::SBAttachInfoGetProcessID(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn set_process_id(&self, pid: lldb_pid_t) {
        unsafe { sys::SBAttachInfoSetProcessID(self.raw, pid) };
    }

    #[allow(missing_docs)]
    pub fn set_executable_path(&self, path: &str) {
        let p = CString::new(path).unwrap();
        unsafe { sys::SBAttachInfoSetExecutable(self.raw, p.as_ptr()) }
    }

    #[allow(missing_docs)]
    pub fn set_executable_filespec(&self, exe_file: SBFileSpec) {
        unsafe { sys::SBAttachInfoSetExecutable2(self.raw, exe_file.raw) }
    }

    #[allow(missing_docs)]
    pub fn wait_for_launch(&self) -> bool {
        unsafe { sys::SBAttachInfoGetWaitForLaunch(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn set_wait_for_launch(&self, wait: bool, async: bool) {
        unsafe { sys::SBAttachInfoSetWaitForLaunch2(self.raw, wait, async) };
    }

    #[allow(missing_docs)]
    pub fn ignore_existing(&self) -> bool {
        unsafe { sys::SBAttachInfoGetIgnoreExisting(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn set_ignore_existing(&self, b: bool) {
        unsafe { sys::SBAttachInfoSetIgnoreExisting(self.raw, b) }
    }

    #[allow(missing_docs)]
    pub fn resume_count(&self) -> u32 {
        unsafe { sys::SBAttachInfoGetResumeCount(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn set_resume_count(&self, c: u32) {
        unsafe { sys::SBAttachInfoSetResumeCount(self.raw, c) }
    }

    #[allow(missing_docs)]
    pub fn process_plugin_name(&self) -> Option<&str> {
        unsafe {
            match CStr::from_ptr(sys::SBAttachInfoGetProcessPluginName(self.raw)).to_str() {
                Ok(s) => Some(s),
                _ => None,
            }
        }
    }

    #[allow(missing_docs)]
    pub fn set_process_plugin_name(&self, plugin: &str) {
        let plugin = CString::new(plugin).unwrap();
        unsafe { sys::SBAttachInfoSetProcessPluginName(self.raw, plugin.as_ptr()) };
    }

    #[allow(missing_docs)]
    pub fn user_id(&self) -> Option<u32> {
        if unsafe { sys::SBAttachInfoUserIDIsValid(self.raw) } {
            Some(unsafe { sys::SBAttachInfoGetUserID(self.raw) })
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn set_user_id(&self, uid: u32) {
        unsafe { sys::SBAttachInfoSetUserID(self.raw, uid) };
    }

    #[allow(missing_docs)]
    pub fn group_id(&self) -> Option<u32> {
        if unsafe { sys::SBAttachInfoGroupIDIsValid(self.raw) } {
            Some(unsafe { sys::SBAttachInfoGetGroupID(self.raw) })
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn set_group_id(&self, gid: u32) {
        unsafe { sys::SBAttachInfoSetGroupID(self.raw, gid) };
    }

    #[allow(missing_docs)]
    pub fn effective_user_id(&self) -> Option<u32> {
        if unsafe { sys::SBAttachInfoEffectiveUserIDIsValid(self.raw) } {
            Some(unsafe { sys::SBAttachInfoGetEffectiveUserID(self.raw) })
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn set_effective_user_id(&self, uid: u32) {
        unsafe { sys::SBAttachInfoSetEffectiveUserID(self.raw, uid) };
    }

    #[allow(missing_docs)]
    pub fn effective_group_id(&self) -> Option<u32> {
        if unsafe { sys::SBAttachInfoEffectiveGroupIDIsValid(self.raw) } {
            Some(unsafe { sys::SBAttachInfoGetEffectiveGroupID(self.raw) })
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn set_effective_group_id(&self, gid: u32) {
        unsafe { sys::SBAttachInfoSetEffectiveGroupID(self.raw, gid) };
    }

    #[allow(missing_docs)]
    pub fn parent_process_id(&self) -> Option<lldb_pid_t> {
        if unsafe { sys::SBAttachInfoParentProcessIDIsValid(self.raw) } {
            Some(unsafe { sys::SBAttachInfoGetParentProcessID(self.raw) })
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn set_parent_process_id(&self, ppid: lldb_pid_t) {
        unsafe { sys::SBAttachInfoSetParentProcessID(self.raw, ppid) };
    }

    /// Get the listener that will be used to receive process events.
    ///
    /// If no listener has been set via a call to
    /// `SBAttachInfo::set_listener()`, then an invalid `SBListener` will be
    /// returned (`SBListener::is_valid()` will return `false`). If a listener
    /// has been set, then the valid listener object will be returned.
    pub fn listener(&self) -> SBListener {
        SBListener::from(unsafe { sys::SBAttachInfoGetListener(self.raw) })
    }

    /// Set the listener that will be used to receive process events.
    ///
    /// By default the [`SBDebugger`], which has a listener,
    /// that the [`SBTarget`] belongs to will listen for the
    /// process events. Calling this function allows a different
    /// listener to be used to listen for process events.
    ///
    /// [`SBDebugger`]: struct.SBDebugger.html
    /// [`SBTarget`]: struct.SBTarget.html
    pub fn set_listener(&self, listener: SBListener) {
        unsafe { sys::SBAttachInfoSetListener(self.raw, listener.raw) };
    }
}

impl Clone for SBAttachInfo {
    fn clone(&self) -> SBAttachInfo {
        SBAttachInfo {
            raw: unsafe { sys::CloneSBAttachInfo(self.raw) },
        }
    }
}

impl Default for SBAttachInfo {
    fn default() -> SBAttachInfo {
        SBAttachInfo::new()
    }
}

impl Drop for SBAttachInfo {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBAttachInfo(self.raw) };
    }
}

impl From<sys::SBAttachInfoRef> for SBAttachInfo {
    fn from(raw: sys::SBAttachInfoRef) -> SBAttachInfo {
        SBAttachInfo { raw }
    }
}

unsafe impl Send for SBAttachInfo {}
unsafe impl Sync for SBAttachInfo {}
<|endoftext|>


<commit_before>//! Get project by id.
//!
//! https://docs.gitlab.com/ce/api/projects.html#get-single-project
//!
//! # Get single project
//!
//! Get a specific project, identified by project ID or NAMESPACE/PROJECT_NAME, which is owned by
//! the authenticated user.
//! If using namespaced projects call make sure that the NAMESPACE/PROJECT_NAME is URL-encoded,
//! eg. `/api/v3/projects/diaspora%2Fdiaspora` (where `/` is represented by `%2F`).
//!
//! ```text
//! GET /projects/ID
//! ```
//!
//! Parameters:
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `id` | integer/string | yes | The ID or NAMESPACE/PROJECT_NAME of the project |

use BuildQuery;

#[derive(Debug, Clone)]
pub enum ListingId {
    Id(i64),
    NamespaceProject(String),
}

#[derive(Default, Debug, Clone)]
pub struct Listing {
    /// The ID or NAMESPACE/PROJECT_NAME of the project
    id:  Option<ListingId>,
}

impl Listing {
    pub fn new() -> Listing {
        Default::default()
    }
    pub fn id(&mut self, id: ListingId) -> &mut Listing {
        self.id = Some(id);
        self
    }
}

impl BuildQuery for Listing {
    fn build_query(&self) -> String {

        let mut query = String::from("projects");

        let amp_char = "&";
        let none_char = "";
        let mut split_char = &none_char;

        // Append a "?" only if at least one of the `Option` is `Some(_)` or if
        // strings contain something.
        query.push_str(match &self.id {
            &None => "",
            _ => "?",
        });

        self.id.clone().map(|id| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("id=");
            query.push_str(&match id {
                ListingId::Id(id) => id.to_string(),
                ListingId::NamespaceProject(s) => s.replace("/", "%2F"),
            });
        });

        query
    }
}

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

    #[test]
    fn projects_build_query_default() {
        let expected_string = "projects";
        let listing: Listing = Default::default();
        let query = listing.build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects";
        let listing = Listing::new();
        let query = listing.build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn projects_build_query_id() {
        let expected_string = "projects?id=123";
        let query = Listing::new().id(ListingId::Id(123)).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?id=group%2Fproject";
        let query = Listing::new().id(ListingId::NamespaceProject("group/project".to_string())).build_query();
        assert_eq!(query, expected_string);
    }
}
<commit_msg>Fix project ids<commit_after>//! Get project by id.
//!
//! https://docs.gitlab.com/ce/api/projects.html#get-single-project
//!
//! # Get single project
//!
//! Get a specific project, identified by project ID or NAMESPACE/PROJECT_NAME, which is owned by
//! the authenticated user.
//! If using namespaced projects call make sure that the NAMESPACE/PROJECT_NAME is URL-encoded,
//! eg. `/api/v3/projects/diaspora%2Fdiaspora` (where `/` is represented by `%2F`).
//!
//! ```text
//! GET /projects/ID
//! ```
//!
//! Parameters:
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `id` | integer/string | yes | The ID or NAMESPACE/PROJECT_NAME of the project |

use BuildQuery;

#[derive(Debug, Clone)]
pub enum ListingId {
    Id(i64),
    NamespaceProject(String),
}

#[derive(Default, Debug, Clone)]
pub struct Listing {
    /// The ID or NAMESPACE/PROJECT_NAME of the project
    id:  Option<ListingId>,
}

impl Listing {
    pub fn new(id: ListingId) -> Listing {
        Listing { id: Some(id) }
    }
}

impl BuildQuery for Listing {
    fn build_query(&self) -> String {

        let mut query = String::from("projects/");

        self.id.clone().map(|id| {
            query.push_str(&match id {
                ListingId::Id(id) => id.to_string(),
                ListingId::NamespaceProject(s) => s.replace("/", "%2F"),
            });
        });

        query
    }
}

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

    const TEST_PROJECT_ID: i64 = 123;
    const TEST_PROJECT_NAME: &'static str = "group/project";

    #[test]
    fn projects_build_query_id() {
        let expected_string = format!("projects/{}", TEST_PROJECT_ID);
        let query = Listing::new(ListingId::Id(123)).build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/{}", TEST_PROJECT_NAME.to_string().replace("/", "%2F"));
        let query = Listing::new(ListingId::NamespaceProject(TEST_PROJECT_NAME.to_string())).build_query();
        assert_eq!(query, expected_string);
    }
}
<|endoftext|>


<commit_before>// FIXME: This may be better in procps
enum PidColumns {
    // Columns go here
}

// Implement FromStr to allow parsing a list of columns specified by a user
// impl FromStr for PidColumns {

// Implement ToStr to get a list of columns specified by a user
// impl ToStr for PidColumns {
<commit_msg>Add samples of PidCols<commit_after>use std::str::FromStr;

// FIXME: This may be better in procps
enum PidCols {
    Pid,
    Ppid
}

// Implement FromStr to allow parsing a list of columns specified by a user
impl FromStr for PidCols {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(match s {
            "pid" => PidCols::Pid,
            "ppid" => PidCols::Ppid,
            _ => return Err(()),
        })
    }
}

// Implement ToStr to get a list of columns specified by a user
// impl ToStr for PidColumns {
// }
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate rand;

use sdl2::audio::{AudioCallback, AudioSpecDesired};

struct MyCallback {
    volume: f32
}
impl AudioCallback for MyCallback {
    pub type Channel = f32;

    fn callback(&mut self, out: &mut [f32]) {
        use self::rand::{Rng, thread_rng};
        let mut rng = thread_rng();

        // Generate white noise
        for x in out.iter_mut() {
            *x = (rng.next_f32()*2.0 - 1.0) * self.volume;
        }
    }
}

fn main() {
    let _sdl_context = sdl2::init(sdl2::INIT_AUDIO).unwrap();

    let desired_spec = AudioSpecDesired {
        freq: 44100,
        channels: 1,
        samples: 0,
        callback: MyCallback { volume: 0.5 },
    };

    // None: use default device
    // false: Playback
    let mut device = match desired_spec.open_audio_device(None, false) {
        Ok(device) => device,
        Err(s) => panic!("{:?}", s)
    };

    // Show obtained AudioSpec
    println!("{:?}", device.get_spec());

    // Start playback
    device.resume();

    // Play for 1 second
    sdl2::timer::delay(1000);

    {
        // Acquire a lock. This lets us read and modify callback data.
        let mut lock = device.lock();
        (*lock).volume = 0.25;
        // Lock guard is dropped here
    }

    // Play for another second
    sdl2::timer::delay(1000);

    // Device is automatically closed when dropped
}
<commit_msg>Fix test for rustc 1.0.0-dev (c9b03c24e 2015-03-12) (built 2015-03-13)<commit_after>extern crate sdl2;
extern crate rand;

use sdl2::audio::{AudioCallback, AudioSpecDesired};

struct MyCallback {
    volume: f32
}
impl AudioCallback for MyCallback {
    type Channel = f32;

    fn callback(&mut self, out: &mut [f32]) {
        use self::rand::{Rng, thread_rng};
        let mut rng = thread_rng();

        // Generate white noise
        for x in out.iter_mut() {
            *x = (rng.next_f32()*2.0 - 1.0) * self.volume;
        }
    }
}

fn main() {
    let _sdl_context = sdl2::init(sdl2::INIT_AUDIO).unwrap();

    let desired_spec = AudioSpecDesired {
        freq: 44100,
        channels: 1,
        samples: 0,
        callback: MyCallback { volume: 0.5 },
    };

    // None: use default device
    // false: Playback
    let mut device = match desired_spec.open_audio_device(None, false) {
        Ok(device) => device,
        Err(s) => panic!("{:?}", s)
    };

    // Show obtained AudioSpec
    println!("{:?}", device.get_spec());

    // Start playback
    device.resume();

    // Play for 1 second
    sdl2::timer::delay(1000);

    {
        // Acquire a lock. This lets us read and modify callback data.
        let mut lock = device.lock();
        (*lock).volume = 0.25;
        // Lock guard is dropped here
    }

    // Play for another second
    sdl2::timer::delay(1000);

    // Device is automatically closed when dropped
}
<|endoftext|>


<commit_before>use std::{cmp::min, fs::File, io, mem, num::Wrapping, path::PathBuf, time::Duration};

use clap::Parser;
use pgn_reader::{BufferedReader, Color, RawHeader, SanPlus, Skip, Visitor};
use rand::{distributions::OpenClosed01, rngs::SmallRng, Rng, SeedableRng};
use serde::Serialize;
use serde_with::{serde_as, DisplayFromStr, SpaceSeparator, StringWithSeparator};

const BATCH_SIZE: usize = 100;

#[derive(Debug, Serialize, Copy, Clone)]
#[serde(rename_all = "camelCase")]
enum Speed {
    UltraBullet,
    Bullet,
    Blitz,
    Rapid,
    Classical,
    Correspondence,
}

impl Speed {
    fn from_seconds_and_increment(seconds: u64, increment: u64) -> Speed {
        let total = seconds + 40 * increment;

        if total < 30 {
            Speed::UltraBullet
        } else if total < 180 {
            Speed::Bullet
        } else if total < 480 {
            Speed::Blitz
        } else if total < 1500 {
            Speed::Rapid
        } else if total < 21_600 {
            Speed::Classical
        } else {
            Speed::Correspondence
        }
    }

    fn from_bytes(bytes: &[u8]) -> Result<Speed, ()> {
        if bytes == b"-" {
            return Ok(Speed::Correspondence);
        }

        let mut parts = bytes.splitn(2, |ch| *ch == b'+');
        let seconds = btoi::btou(parts.next().ok_or(())?).map_err(|_| ())?;
        let increment = btoi::btou(parts.next().ok_or(())?).map_err(|_| ())?;
        Ok(Speed::from_seconds_and_increment(seconds, increment))
    }
}

struct Importer {
    endpoint: String,
    filename: PathBuf,
    client: reqwest::blocking::Client,
    rng: SmallRng,
    spinner_idx: Wrapping<usize>,

    current: Game,
    skip: bool,
    batch: Vec<Game>,
}

#[serde_as]
#[derive(Default, Serialize, Debug)]
struct Game {
    variant: Option<String>,
    speed: Option<Speed>,
    fen: Option<String>,
    id: Option<String>,
    date: Option<String>,
    white: Player,
    black: Player,
    #[serde_as(as = "Option<DisplayFromStr>")]
    winner: Option<Color>,
    #[serde_as(as = "StringWithSeparator<SpaceSeparator, SanPlus>")]
    moves: Vec<SanPlus>,
}

#[derive(Default, Serialize, Debug)]
struct Player {
    name: Option<String>,
    rating: Option<u16>,
}

impl Importer {
    fn new(endpoint: &str, filename: PathBuf) -> Importer {
        Importer {
            endpoint: endpoint.to_owned(),
            filename,
            client: reqwest::blocking::Client::builder()
                .timeout(Duration::from_secs(60))
                .build()
                .expect("client"),
            rng: SmallRng::from_seed([
                0x19, 0x29, 0xab, 0x17, 0xc6, 0xfa, 0xb0, 0xe9, 0x4b, 0x44, 0xd8, 0x07, 0x09, 0xbf,
                0x1d, 0x87, 0xbd, 0xd8, 0xb3, 0x2f, 0xe1, 0xe2, 0xa0, 0x1a, 0x9e, 0x30, 0x98, 0xd7,
                0xef, 0xd5, 0x7a, 0x1d,
            ]),
            spinner_idx: Wrapping(0),
            current: Game::default(),
            skip: false,
            batch: Vec::with_capacity(BATCH_SIZE),
        }
    }

    pub fn send(&mut self) {
        // println!("{}", serde_json::to_string(&self.batch).expect("serialize"));

        let res = self
            .client
            .put(format!("{}/import/lichess", self.endpoint))
            .json(&self.batch)
            .send()
            .expect("send batch");

        self.spinner_idx += Wrapping(1);
        let spinner = &['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];

        println!(
            "{} {:?}: {}: {} - {}",
            spinner[self.spinner_idx.0 % spinner.len()],
            self.filename,
            self.batch
                .last()
                .and_then(|g| g.date.as_ref())
                .unwrap_or(&String::new()),
            res.status(),
            res.text().expect("decode response")
        );

        self.batch.clear();
    }
}

impl Visitor for Importer {
    type Result = ();

    fn begin_game(&mut self) {
        self.skip = false;
        self.current = Game::default();
    }

    fn header(&mut self, key: &[u8], value: RawHeader<'_>) {
        if key == b"White" {
            self.current.white.name = Some(value.decode_utf8().expect("White").into_owned());
        } else if key == b"Black" {
            self.current.black.name = Some(value.decode_utf8().expect("Black").into_owned());
        } else if key == b"WhiteElo" {
            if value.as_bytes() != b"?" {
                self.current.white.rating = Some(btoi::btoi(value.as_bytes()).expect("WhiteElo"));
            }
        } else if key == b"BlackElo" {
            if value.as_bytes() != b"?" {
                self.current.black.rating = Some(btoi::btoi(value.as_bytes()).expect("BlackElo"));
            }
        } else if key == b"TimeControl" {
            self.current.speed = Some(Speed::from_bytes(value.as_bytes()).expect("TimeControl"));
        } else if key == b"Variant" {
            self.current.variant = Some(value.decode_utf8().expect("Variant").into_owned());
        } else if key == b"Date" || key == b"UTCDate" {
            self.current.date = Some(value.decode_utf8().expect("Date").into_owned());
        } else if key == b"WhiteTitle" || key == b"BlackTitle" {
            if value.as_bytes() == b"BOT" {
                self.skip = true;
            }
        } else if key == b"Site" {
            self.current.id = Some(
                String::from_utf8(
                    value
                        .as_bytes()
                        .rsplitn(2, |ch| *ch == b'/')
                        .next()
                        .expect("Site")
                        .to_owned(),
                )
                .expect("Site"),
            );
        } else if key == b"Result" {
            match value.as_bytes() {
                b"1-0" => self.current.winner = Some(Color::White),
                b"0-1" => self.current.winner = Some(Color::Black),
                b"1/2-1/2" => self.current.winner = None,
                _ => self.skip = true,
            }
        } else if key == b"FEN" {
            if value.as_bytes() == b"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" {
                // https://github.com/ornicar/lichess-db/issues/40
                self.current.fen = None;
            } else {
                self.current.fen = Some(value.decode_utf8().expect("FEN").into_owned());
            }
        }
    }

    fn end_headers(&mut self) -> Skip {
        let rating =
            (self.current.white.rating.unwrap_or(0) + self.current.black.rating.unwrap_or(0)) / 2;

        let standard = self
            .current
            .variant
            .as_ref()
            .map_or(true, |name| name == "Standard");

        let probability = if standard {
            match self.current.speed.unwrap_or(Speed::Correspondence) {
                Speed::Correspondence | Speed::Classical => 1.00,

                _ if rating >= 2500 => 1.00,

                Speed::Rapid if rating >= 2200 => 1.00,
                Speed::Rapid if rating >= 2000 => 0.50,
                Speed::Rapid if rating >= 1800 => 0.28,
                Speed::Rapid if rating >= 1600 => 0.24,

                Speed::Blitz if rating >= 2200 => 0.24,
                Speed::Blitz if rating >= 2000 => 0.11,
                Speed::Blitz if rating >= 1600 => 0.08,

                Speed::Bullet if rating >= 2200 => 0.30,
                Speed::Bullet if rating >= 2000 => 0.17,
                Speed::Bullet if rating >= 1600 => 0.11,

                Speed::UltraBullet => 1.00,

                _ => 0.02,
            }
        } else {
            // variant games
            if rating >= 1600 {
                1.00
            } else {
                0.50
            }
        };

        let accept = min(
            self.current.white.rating.unwrap_or(0),
            self.current.black.rating.unwrap_or(0),
        ) >= 1501
            && probability >= self.rng.sample(OpenClosed01)
            && !self.skip;

        self.skip = !accept;
        Skip(self.skip)
    }

    fn san(&mut self, san: SanPlus) {
        self.current.moves.push(san);
    }

    fn begin_variation(&mut self) -> Skip {
        Skip(true) // stay in the mainline
    }

    fn end_game(&mut self) {
        if !self.skip {
            self.batch
                .push(mem::replace(&mut self.current, Default::default()));

            if self.batch.len() >= BATCH_SIZE {
                self.send();
            }
        }
    }
}

#[derive(Parser)]
struct Args {
    #[clap(long, default_value = "http://localhost:9002")]
    endpoint: String,
    pgns: Vec<PathBuf>,
}

fn main() -> Result<(), io::Error> {
    let args = Args::parse();

    for arg in args.pgns {
        let file = File::open(&arg)?;

        let uncompressed: Box<dyn io::Read> = if arg.ends_with(".bz2") {
            Box::new(bzip2::read::MultiBzDecoder::new(file))
        } else {
            Box::new(file)
        };

        let mut reader = BufferedReader::new(uncompressed);

        let mut importer = Importer::new(&args.endpoint, arg);
        reader.read_all(&mut importer)?;
        importer.send();
    }

    Ok(())
}
<commit_msg>show info about opened file<commit_after>use std::{cmp::min, fs::File, io, mem, num::Wrapping, path::PathBuf, time::Duration};

use clap::Parser;
use pgn_reader::{BufferedReader, Color, RawHeader, SanPlus, Skip, Visitor};
use rand::{distributions::OpenClosed01, rngs::SmallRng, Rng, SeedableRng};
use serde::Serialize;
use serde_with::{serde_as, DisplayFromStr, SpaceSeparator, StringWithSeparator};

const BATCH_SIZE: usize = 100;

#[derive(Debug, Serialize, Copy, Clone)]
#[serde(rename_all = "camelCase")]
enum Speed {
    UltraBullet,
    Bullet,
    Blitz,
    Rapid,
    Classical,
    Correspondence,
}

impl Speed {
    fn from_seconds_and_increment(seconds: u64, increment: u64) -> Speed {
        let total = seconds + 40 * increment;

        if total < 30 {
            Speed::UltraBullet
        } else if total < 180 {
            Speed::Bullet
        } else if total < 480 {
            Speed::Blitz
        } else if total < 1500 {
            Speed::Rapid
        } else if total < 21_600 {
            Speed::Classical
        } else {
            Speed::Correspondence
        }
    }

    fn from_bytes(bytes: &[u8]) -> Result<Speed, ()> {
        if bytes == b"-" {
            return Ok(Speed::Correspondence);
        }

        let mut parts = bytes.splitn(2, |ch| *ch == b'+');
        let seconds = btoi::btou(parts.next().ok_or(())?).map_err(|_| ())?;
        let increment = btoi::btou(parts.next().ok_or(())?).map_err(|_| ())?;
        Ok(Speed::from_seconds_and_increment(seconds, increment))
    }
}

struct Importer {
    endpoint: String,
    filename: PathBuf,
    client: reqwest::blocking::Client,
    rng: SmallRng,
    spinner_idx: Wrapping<usize>,

    current: Game,
    skip: bool,
    batch: Vec<Game>,
}

#[serde_as]
#[derive(Default, Serialize, Debug)]
struct Game {
    variant: Option<String>,
    speed: Option<Speed>,
    fen: Option<String>,
    id: Option<String>,
    date: Option<String>,
    white: Player,
    black: Player,
    #[serde_as(as = "Option<DisplayFromStr>")]
    winner: Option<Color>,
    #[serde_as(as = "StringWithSeparator<SpaceSeparator, SanPlus>")]
    moves: Vec<SanPlus>,
}

#[derive(Default, Serialize, Debug)]
struct Player {
    name: Option<String>,
    rating: Option<u16>,
}

impl Importer {
    fn new(endpoint: &str, filename: PathBuf) -> Importer {
        Importer {
            endpoint: endpoint.to_owned(),
            filename,
            client: reqwest::blocking::Client::builder()
                .timeout(Duration::from_secs(60))
                .build()
                .expect("client"),
            rng: SmallRng::from_seed([
                0x19, 0x29, 0xab, 0x17, 0xc6, 0xfa, 0xb0, 0xe9, 0x4b, 0x44, 0xd8, 0x07, 0x09, 0xbf,
                0x1d, 0x87, 0xbd, 0xd8, 0xb3, 0x2f, 0xe1, 0xe2, 0xa0, 0x1a, 0x9e, 0x30, 0x98, 0xd7,
                0xef, 0xd5, 0x7a, 0x1d,
            ]),
            spinner_idx: Wrapping(0),
            current: Game::default(),
            skip: false,
            batch: Vec::with_capacity(BATCH_SIZE),
        }
    }

    pub fn send(&mut self) {
        // println!("{}", serde_json::to_string(&self.batch).expect("serialize"));

        let res = self
            .client
            .put(format!("{}/import/lichess", self.endpoint))
            .json(&self.batch)
            .send()
            .expect("send batch");

        self.spinner_idx += Wrapping(1);
        let spinner = &['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];

        println!(
            "{} {:?}: {}: {} - {}",
            spinner[self.spinner_idx.0 % spinner.len()],
            self.filename,
            self.batch
                .last()
                .and_then(|g| g.date.as_ref())
                .unwrap_or(&String::new()),
            res.status(),
            res.text().expect("decode response")
        );

        self.batch.clear();
    }
}

impl Visitor for Importer {
    type Result = ();

    fn begin_game(&mut self) {
        self.skip = false;
        self.current = Game::default();
    }

    fn header(&mut self, key: &[u8], value: RawHeader<'_>) {
        if key == b"White" {
            self.current.white.name = Some(value.decode_utf8().expect("White").into_owned());
        } else if key == b"Black" {
            self.current.black.name = Some(value.decode_utf8().expect("Black").into_owned());
        } else if key == b"WhiteElo" {
            if value.as_bytes() != b"?" {
                self.current.white.rating = Some(btoi::btoi(value.as_bytes()).expect("WhiteElo"));
            }
        } else if key == b"BlackElo" {
            if value.as_bytes() != b"?" {
                self.current.black.rating = Some(btoi::btoi(value.as_bytes()).expect("BlackElo"));
            }
        } else if key == b"TimeControl" {
            self.current.speed = Some(Speed::from_bytes(value.as_bytes()).expect("TimeControl"));
        } else if key == b"Variant" {
            self.current.variant = Some(value.decode_utf8().expect("Variant").into_owned());
        } else if key == b"Date" || key == b"UTCDate" {
            self.current.date = Some(value.decode_utf8().expect("Date").into_owned());
        } else if key == b"WhiteTitle" || key == b"BlackTitle" {
            if value.as_bytes() == b"BOT" {
                self.skip = true;
            }
        } else if key == b"Site" {
            self.current.id = Some(
                String::from_utf8(
                    value
                        .as_bytes()
                        .rsplitn(2, |ch| *ch == b'/')
                        .next()
                        .expect("Site")
                        .to_owned(),
                )
                .expect("Site"),
            );
        } else if key == b"Result" {
            match value.as_bytes() {
                b"1-0" => self.current.winner = Some(Color::White),
                b"0-1" => self.current.winner = Some(Color::Black),
                b"1/2-1/2" => self.current.winner = None,
                _ => self.skip = true,
            }
        } else if key == b"FEN" {
            if value.as_bytes() == b"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" {
                // https://github.com/ornicar/lichess-db/issues/40
                self.current.fen = None;
            } else {
                self.current.fen = Some(value.decode_utf8().expect("FEN").into_owned());
            }
        }
    }

    fn end_headers(&mut self) -> Skip {
        let rating =
            (self.current.white.rating.unwrap_or(0) + self.current.black.rating.unwrap_or(0)) / 2;

        let standard = self
            .current
            .variant
            .as_ref()
            .map_or(true, |name| name == "Standard");

        let probability = if standard {
            match self.current.speed.unwrap_or(Speed::Correspondence) {
                Speed::Correspondence | Speed::Classical => 1.00,

                _ if rating >= 2500 => 1.00,

                Speed::Rapid if rating >= 2200 => 1.00,
                Speed::Rapid if rating >= 2000 => 0.50,
                Speed::Rapid if rating >= 1800 => 0.28,
                Speed::Rapid if rating >= 1600 => 0.24,

                Speed::Blitz if rating >= 2200 => 0.24,
                Speed::Blitz if rating >= 2000 => 0.11,
                Speed::Blitz if rating >= 1600 => 0.08,

                Speed::Bullet if rating >= 2200 => 0.30,
                Speed::Bullet if rating >= 2000 => 0.17,
                Speed::Bullet if rating >= 1600 => 0.11,

                Speed::UltraBullet => 1.00,

                _ => 0.02,
            }
        } else {
            // variant games
            if rating >= 1600 {
                1.00
            } else {
                0.50
            }
        };

        let accept = min(
            self.current.white.rating.unwrap_or(0),
            self.current.black.rating.unwrap_or(0),
        ) >= 1501
            && probability >= self.rng.sample(OpenClosed01)
            && !self.skip;

        self.skip = !accept;
        Skip(self.skip)
    }

    fn san(&mut self, san: SanPlus) {
        self.current.moves.push(san);
    }

    fn begin_variation(&mut self) -> Skip {
        Skip(true) // stay in the mainline
    }

    fn end_game(&mut self) {
        if !self.skip {
            self.batch
                .push(mem::replace(&mut self.current, Default::default()));

            if self.batch.len() >= BATCH_SIZE {
                self.send();
            }
        }
    }
}

#[derive(Parser)]
struct Args {
    #[clap(long, default_value = "http://localhost:9002")]
    endpoint: String,
    pgns: Vec<PathBuf>,
}

fn main() -> Result<(), io::Error> {
    let args = Args::parse();

    for arg in args.pgns {
        let file = File::open(&arg)?;

        let uncompressed: Box<dyn io::Read> = if arg.ends_with(".bz2") {
            println!("Reading compressed {:?} ...", arg);
            Box::new(bzip2::read::MultiBzDecoder::new(file))
        } else {
            println!("Reading {:?} ...", arg);
            Box::new(file)
        };

        let mut reader = BufferedReader::new(uncompressed);

        let mut importer = Importer::new(&args.endpoint, arg);
        reader.read_all(&mut importer)?;
        importer.send();
    }

    Ok(())
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate petgraph;
extern crate test;

use test::Bencher;
use petgraph::prelude::*;

use petgraph::{EdgeType};
use petgraph::stable_graph::{
    node_index,
};

/// An almost full set
const FULL_A: &'static str = "
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 0 1 1 1 0 1
 1 1 1 1 1 1 1 1 1 1
";

#[bench]
fn full_edges_default(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);

    bench.iter(|| a.edges(node_index(1)).count())
}

#[bench]
fn full_edges_out(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);
    bench.iter(|| a.edges_directed(node_index(1), Outgoing).count())
}
#[bench]
fn full_edges_in(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);

    bench.iter(|| a.edges_directed(node_index(1), Incoming).count())
}

#[bench]
fn neighbors_default(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);

    bench.iter(|| a.neighbors(node_index(1)).count())
}

#[bench]
fn neighbors_out(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);
    bench.iter(|| a.neighbors_directed(node_index(1), Outgoing).count())
}
#[bench]
fn neighbors_in(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);

    bench.iter(|| a.neighbors_directed(node_index(1), Incoming).count())
}

/// Parse a text adjacency matrix format into a directed graph
fn parse_stable_graph<Ty: EdgeType>(s: &str) -> StableGraph<(), (), Ty>
{
    let mut gr = StableGraph::default();
    let s = s.trim();
    let lines = s.lines().filter(|l| !l.is_empty());
    for (row, line) in lines.enumerate() {
        for (col, word) in line.split(' ')
                                .filter(|s| s.len() > 0)
                                .enumerate()
        {
            let has_edge = word.parse::<i32>().unwrap();
            assert!(has_edge == 0 || has_edge == 1);
            if has_edge == 0 {
                continue;
            }
            while col >= gr.node_count() || row >= gr.node_count() {
                gr.add_node(());
            }
            gr.update_edge(node_index(row), node_index(col), ());
        }
    }
    gr
}

<commit_msg>Add benchmark using scc<commit_after>#![feature(test)]

extern crate petgraph;
extern crate test;

use test::Bencher;
use petgraph::prelude::*;

use petgraph::{EdgeType};
use petgraph::stable_graph::{
    node_index,
};

/// An almost full set
const FULL_A: &'static str = "
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 0 1 1 1 0 1
 1 1 1 1 1 1 1 1 1 1
";

const BIGGER: &'static str = "
 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 1 0 1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 1 0 1 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0
 0 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0
 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 1 0 0
 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0
 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1
 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 1 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 1
 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 1 1 0 1 1 1 0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 1
 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 1 0
 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
 1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 1 0 1 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 1 0 1 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0
 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0
 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0
 0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 1 0 0
 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 1 0
 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1
 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 1 0 0
 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0
 0 1 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1
 0 1 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 0
 0 1 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 1
 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1
 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 1
 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 1 0
";

#[bench]
fn full_edges_default(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);

    bench.iter(|| a.edges(node_index(1)).count())
}

#[bench]
fn full_edges_out(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);
    bench.iter(|| a.edges_directed(node_index(1), Outgoing).count())
}
#[bench]
fn full_edges_in(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);

    bench.iter(|| a.edges_directed(node_index(1), Incoming).count())
}

#[bench]
fn neighbors_default(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);

    bench.iter(|| a.neighbors(node_index(1)).count())
}

#[bench]
fn neighbors_out(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);
    bench.iter(|| a.neighbors_directed(node_index(1), Outgoing).count())
}
#[bench]
fn neighbors_in(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);

    bench.iter(|| a.neighbors_directed(node_index(1), Incoming).count())
}

#[bench]
fn sccs_stable_graph(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(BIGGER);
    bench.iter(|| petgraph::algo::scc(&a));
}

#[bench]
fn sccs_graph(bench: &mut Bencher)
{
    let a = parse_graph::<Directed>(BIGGER);
    bench.iter(|| petgraph::algo::scc(&a));
}

/// Parse a text adjacency matrix format into a directed graph
fn parse_stable_graph<Ty: EdgeType>(s: &str) -> StableGraph<(), (), Ty>
{
    let mut gr = StableGraph::default();
    let s = s.trim();
    let lines = s.lines().filter(|l| !l.is_empty());
    for (row, line) in lines.enumerate() {
        for (col, word) in line.split(' ')
                                .filter(|s| s.len() > 0)
                                .enumerate()
        {
            let has_edge = word.parse::<i32>().unwrap();
            assert!(has_edge == 0 || has_edge == 1);
            if has_edge == 0 {
                continue;
            }
            while col >= gr.node_count() || row >= gr.node_count() {
                gr.add_node(());
            }
            gr.update_edge(node_index(row), node_index(col), ());
        }
    }
    gr
}

/// Parse a text adjacency matrix format into a directed graph
fn parse_graph<Ty: EdgeType>(s: &str) -> Graph<(), (), Ty>
{
    let mut gr = Graph::with_capacity(0, 0);
    let s = s.trim();
    let lines = s.lines().filter(|l| !l.is_empty());
    for (row, line) in lines.enumerate() {
        for (col, word) in line.split(' ')
                                .filter(|s| s.len() > 0)
                                .enumerate()
        {
            let has_edge = word.parse::<i32>().unwrap();
            assert!(has_edge == 0 || has_edge == 1);
            if has_edge == 0 {
                continue;
            }
            while col >= gr.node_count() || row >= gr.node_count() {
                gr.add_node(());
            }
            gr.update_edge(node_index(row), node_index(col), ());
        }
    }
    gr
}

<|endoftext|>


<commit_before>extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use websocket::message::OwnedMessage;
use websocket::server::InvalidConnection;
use websocket::async::Server;

use tokio_core::reactor::{Handle, Core};

use futures::{Future, Sink, Stream};
use futures::future::{self, Loop};
use futures::sync::mpsc;
use futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::thread;
use std::rc::Rc;
use std::fmt::Debug;
use std::time::Duration;
use std::ops::Deref;

fn main() {
    let mut core = Core::new().expect("Failed to create Tokio event loop");
    let handle = core.handle();
    let remote = core.remote();
    let server = Server::bind("localhost:8081", &handle).expect("Failed to create server");
    let pool = Rc::new(CpuPool::new_num_cpus());
    let connections = Arc::new(RwLock::new(Vec::new()));
    let state = Arc::new(RwLock::new(State::new()));
    let (read_channel_out, read_channel_in) = mpsc::unbounded();
    let handle_inner = handle.clone();
    let connections_inner = connections.clone();
    let connection_handler = server.incoming()
        // we don't wanna save the stream if it drops
        .map_err(|InvalidConnection { error, .. }| error)
        .for_each(move |(upgrade, addr)| {
            let connections = connections_inner.clone();
            println!("Got a connection from: {}", addr);
            if !upgrade.protocols().iter().any(|s| s == "rust-websocket") {
                spawn_future(upgrade.reject(), "Upgrade Rejection", &handle_inner);
                return Ok(());
            }
            let read_channel_out = read_channel_out.clone();
            let handle = handle_inner.clone();
            let f = upgrade
                .use_protocol("rust-websocket")
                .accept()
                .and_then(move |(framed, _)| {
                    let (sink, stream) = framed.split();
                    let f = read_channel_out.send(stream);
                    spawn_future(f, "Senk sink to connection pool", &handle);
                    connections.write().unwrap().push(Arc::new(RwLock::new(sink)));
                    Ok(())
                });
            spawn_future(f, "Handle new connection", &handle_inner);
            Ok(())
        })
        .map_err(|_| ());

    let state_read = state.clone();
    let remote_write = remote.clone();
    let read_handler = pool.spawn_fn(|| {
        read_channel_in.for_each(move |stream| {
            let state_read = state_read.clone();
            remote_write.spawn(|_| {
                stream.for_each(move |msg| {
                                    handle_incoming(&mut state_read.write().unwrap(), &msg);
                                    Ok(())
                                })
                    .map_err(|_| ())
            });
            Ok(())
        })
    });

    let (write_channel_out, write_channel_in) = futures::sync::mpsc::unbounded();

    type MessageCodec = websocket::async::MessageCodec<OwnedMessage>;
    type Framed = websocket::client::async::Framed<tokio_core::net::TcpStream, MessageCodec>;
    type SplitSink = futures::stream::SplitSink<Framed>;
    let write_handler = pool.spawn_fn(move || {
        write_channel_in.for_each(move |(sink, state): (Arc<RwLock<SplitSink>>,
                                                        Arc<RwLock<State>>)| {
                let msg = serde_json::to_string(state.read().unwrap().deref()).unwrap();
                println!("Sending message: {}", msg);
                sink.write()
                    .unwrap()
                    .start_send(OwnedMessage::Text(msg))
                    .unwrap();
                sink.write()
                    .unwrap()
                    .poll_complete()
                    .unwrap();
                Ok(())
            })
            .map_err(|_| ())
    });

    let game_loop = pool.spawn_fn(move || {
        future::loop_fn(write_channel_out, move |write_channel_out| {
            thread::sleep(Duration::from_millis(100));
            for conn in connections.write().unwrap().iter() {
                write_channel_out.clone()
                    .send((conn.clone(), state.clone()))
                    .wait()
                    .unwrap();
            }
            match 1 {
                1 => Ok(Loop::Continue(write_channel_out)),
                2 => Ok(Loop::Break(())),
                _ => Err(()),
            }
        })
    });

    let handlers =
        game_loop.select2(connection_handler.select2(read_handler.select(write_handler)));
    core.run(handlers).map_err(|_| println!("err")).unwrap();
}

fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
    where F: Future<Item = I, Error = E> + 'static,
          E: Debug
{
    handle.spawn(f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
                     .map(move |_| println!("{}: Finished.", desc)));
}

fn handle_incoming(_: &mut State, msg: &OwnedMessage) {
    if let OwnedMessage::Text(ref txt) = *msg {
        println!("Received message: {}", txt);
        //state.msg = txt.clone();
    }
}

#[derive(Serialize, Deserialize)]
struct State {
    positions: Vec<Pos>,
}

impl State {
    fn new() -> Self {
        Self { positions: Vec::new() }
    }
}

#[derive(Serialize, Deserialize)]
struct Pos {
    x: i32,
    y: i32,
}

/*
impl Pos {
    fn new(x: i32, y: i32) -> Self {
        Self { x, y }
    }

    fn add_x(&mut self, x: i32) -> &mut Self {
        self.x += x;
        self
    }

    fn add_y(&mut self, y: i32) -> &mut Self {
        self.y += y;
        self
    }

    fn add(&mut self, x: i32, y: i32) -> &mut Self {
        self.x += x;
        self.y += y;
        self
    }
}
*/
<commit_msg>Send async<commit_after>extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use websocket::message::OwnedMessage;
use websocket::server::InvalidConnection;
use websocket::async::Server;

use tokio_core::reactor::{Handle, Core};

use futures::{Future, Sink, Stream};
use futures::future::{self, Loop};
use futures::sync::mpsc;
use futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::thread;
use std::rc::Rc;
use std::fmt::Debug;
use std::time::Duration;
use std::ops::Deref;

fn main() {
    let mut core = Core::new().expect("Failed to create Tokio event loop");
    let handle = core.handle();
    let remote = core.remote();
    let server = Server::bind("localhost:8081", &handle).expect("Failed to create server");
    let pool = Rc::new(CpuPool::new_num_cpus());
    let connections = Arc::new(RwLock::new(Vec::new()));
    let state = Arc::new(RwLock::new(State::new()));
    let (read_channel_out, read_channel_in) = mpsc::unbounded();
    let handle_inner = handle.clone();
    let connections_inner = connections.clone();
    let connection_handler = server.incoming()
        // we don't wanna save the stream if it drops
        .map_err(|InvalidConnection { error, .. }| error)
        .for_each(move |(upgrade, addr)| {
            let connections = connections_inner.clone();
            println!("Got a connection from: {}", addr);
            if !upgrade.protocols().iter().any(|s| s == "rust-websocket") {
                spawn_future(upgrade.reject(), "Upgrade Rejection", &handle_inner);
                return Ok(());
            }
            let read_channel_out = read_channel_out.clone();
            let handle = handle_inner.clone();
            let f = upgrade
                .use_protocol("rust-websocket")
                .accept()
                .and_then(move |(framed, _)| {
                    let (sink, stream) = framed.split();
                    let f = read_channel_out.send(stream);
                    spawn_future(f, "Senk sink to connection pool", &handle);
                    connections.write().unwrap().push(Arc::new(RwLock::new(sink)));
                    Ok(())
                });
            spawn_future(f, "Handle new connection", &handle_inner);
            Ok(())
        })
        .map_err(|_| ());

    let state_read = state.clone();
    let remote_write = remote.clone();
    let read_handler = pool.spawn_fn(|| {
        read_channel_in.for_each(move |stream| {
            let state_read = state_read.clone();
            remote_write.spawn(|_| {
                stream.for_each(move |msg| {
                                    handle_incoming(&mut state_read.write().unwrap(), &msg);
                                    Ok(())
                                })
                    .map_err(|_| ())
            });
            Ok(())
        })
    });

    let (write_channel_out, write_channel_in) = futures::sync::mpsc::unbounded();

    type MessageCodec = websocket::async::MessageCodec<OwnedMessage>;
    type Framed = websocket::client::async::Framed<tokio_core::net::TcpStream, MessageCodec>;
    type SplitSink = futures::stream::SplitSink<Framed>;
    let write_handler = pool.spawn_fn(move || {
        write_channel_in.for_each(move |(sink, state): (Arc<RwLock<SplitSink>>,
                                                        Arc<RwLock<State>>)| {
                let msg = serde_json::to_string(state.read().unwrap().deref()).unwrap();
                println!("Sending message: {}", msg);
                sink.write()
                    .unwrap()
                    .start_send(OwnedMessage::Text(msg))
                    .unwrap();
                sink.write()
                    .unwrap()
                    .poll_complete()
                    .unwrap();
                Ok(())
            })
            .map_err(|_| ())
    });

    let game_loop = pool.spawn_fn(move || {
        future::loop_fn(write_channel_out, move |write_channel_out| {
            thread::sleep(Duration::from_millis(100));
            let connections = connections.clone();
            let state = state.clone();
            let write_channel_out_inner = write_channel_out.clone();
            remote.spawn(move |handle| {
                for conn in connections.write().unwrap().iter() {
                    let f = write_channel_out_inner.clone().send((conn.clone(), state.clone()));
                    spawn_future(f, "Send message to client", handle);
                }
                Ok(())
            });
            match 1 {
                1 => Ok(Loop::Continue(write_channel_out)),
                2 => Ok(Loop::Break(())),
                _ => Err(()),
            }
        })
    });

    let handlers =
        game_loop.select2(connection_handler.select2(read_handler.select(write_handler)));
    core.run(handlers).map_err(|_| println!("err")).unwrap();
}

fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
    where F: Future<Item = I, Error = E> + 'static,
          E: Debug
{
    handle.spawn(f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
                     .map(move |_| println!("{}: Finished.", desc)));
}

fn handle_incoming(_: &mut State, msg: &OwnedMessage) {
    if let OwnedMessage::Text(ref txt) = *msg {
        println!("Received message: {}", txt);
        //state.msg = txt.clone();
    }
}

#[derive(Serialize, Deserialize)]
struct State {
    positions: Vec<Pos>,
}

impl State {
    fn new() -> Self {
        Self { positions: Vec::new() }
    }
}

#[derive(Serialize, Deserialize)]
struct Pos {
    x: i32,
    y: i32,
}

/*
impl Pos {
    fn new(x: i32, y: i32) -> Self {
        Self { x, y }
    }

    fn add_x(&mut self, x: i32) -> &mut Self {
        self.x += x;
        self
    }

    fn add_y(&mut self, y: i32) -> &mut Self {
        self.y += y;
        self
    }

    fn add(&mut self, x: i32, y: i32) -> &mut Self {
        self.x += x;
        self.y += y;
        self
    }
}
*/
<|endoftext|>


<commit_before>struct Container(i32, i32);

// A trait which will check to see if 2 items are stored inside of container.
// Also retrieves first or last value.
trait Contains {
    // Define generic types here which methods will be able utilize.
    type A;
    type B;

    fn contains(&self, &Self::A, &Self::B) -> bool;
    fn first(&self) -> i32;
    fn last(&self) -> i32;
}

impl Contains for Container {
    // Specify what types `A` and `B` are. If the `input` type
    // is `Container(i32, i32)`, the `output` types are determined
    // as `i32` and `i32`.
    type A = i32;
    type B = i32;

    // `&Self::A` and `&self::B` are also valid here.
    fn contains(&self, number: &i32, digit: &i32) -> bool {
        (&self.0 == number) && (&self.1 == digit)
    }
    // Grab the first number.
    fn first(&self) -> i32 { self.0 }

    // Grab the last number.
    fn last(&self) -> i32 { self.1 }
}

fn difference<C: Contains>(container: &C) -> i32 {
    container.last() - container.first()
}

fn main() {
    let number = 3;
    let digit = 10;

    let container = Container(number, digit);

    println!("Does container contain {} and {}: {}",
        &number, &digit,
        container.contains(&number, &digit));
    println!("First number: {}", container.first());
    println!("Last number: {}", container.last());

    println!("The difference is: {}", difference(&container));
}
<commit_msg>Use two instead of 2<commit_after>struct Container(i32, i32);

// A trait which will check to see if two items are stored inside of container.
// Also retrieves first or last value.
trait Contains {
    // Define generic types here which methods will be able utilize.
    type A;
    type B;

    fn contains(&self, &Self::A, &Self::B) -> bool;
    fn first(&self) -> i32;
    fn last(&self) -> i32;
}

impl Contains for Container {
    // Specify what types `A` and `B` are. If the `input` type
    // is `Container(i32, i32)`, the `output` types are determined
    // as `i32` and `i32`.
    type A = i32;
    type B = i32;

    // `&Self::A` and `&self::B` are also valid here.
    fn contains(&self, number: &i32, digit: &i32) -> bool {
        (&self.0 == number) && (&self.1 == digit)
    }
    // Grab the first number.
    fn first(&self) -> i32 { self.0 }

    // Grab the last number.
    fn last(&self) -> i32 { self.1 }
}

fn difference<C: Contains>(container: &C) -> i32 {
    container.last() - container.first()
}

fn main() {
    let number = 3;
    let digit = 10;

    let container = Container(number, digit);

    println!("Does container contain {} and {}: {}",
        &number, &digit,
        container.contains(&number, &digit));
    println!("First number: {}", container.first());
    println!("Last number: {}", container.last());

    println!("The difference is: {}", difference(&container));
}
<|endoftext|>


<commit_before>extern crate rustful;
use rustful::{Server, Router, Request};

fn say_hello(request: &Request) -> ~str {
	let person = match request.variables.find(&~"person") {
		Some(name) => name.to_str(),
		None => ~"stranger"
	};
	format!("Hello, {}!", person.to_str())
}

fn main() {
	let routes = ~[
		("/", say_hello),
		("/:person", say_hello)
	];

	let server = Server {
		router: ~Router::from_vec(routes),
		port: 8080
	};

	server.run();
}<commit_msg>Removed unnecessary to_str<commit_after>extern crate rustful;
use rustful::{Server, Router, Request};

fn say_hello(request: &Request) -> ~str {
	let person = match request.variables.find(&~"person") {
		Some(name) => name.to_str(),
		None => ~"stranger"
	};
	format!("Hello, {}!", person)
}

fn main() {
	let routes = ~[
		("/", say_hello),
		("/:person", say_hello)
	];

	let server = Server {
		router: ~Router::from_vec(routes),
		port: 8080
	};

	server.run();
}<|endoftext|>


<commit_before>#![feature(proc_macro, conservative_impl_trait, generators)]
extern crate bytes;
extern crate futures_await as futures;
extern crate tokio_core;
extern crate tokio_io;

mod cmd;
mod ftp;
mod error;
mod codec;

use std::result;
use std::io;
use futures::prelude::*;
use tokio_core::reactor::Core;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use tokio_core::reactor::Handle;
use tokio_core::net::TcpListener;

use tokio_core::net::TcpStream;

use futures::{Sink, Stream};
use futures::stream::SplitSink;

use tokio_io::AsyncRead;
use tokio_io::codec::Framed;
use codec::FtpCodec;
use error::Result;
use ftp::{Answer, ResultCode};
use std::path::PathBuf;

use cmd::Command;
type Writer = SplitSink<Framed<TcpStream, FtpCodec>>;

struct Client {
    cwd: PathBuf,
    writer: Writer,
}

impl Client {
    fn new(writer: Writer) -> Client {
        Client {
            cwd: PathBuf::from("/"),
            writer,
        }
    }
    #[async]
    fn send(mut self, answer: Answer) -> Result<Self> {
        self.writer = await!(self.writer.send(answer))?;
        Ok(self)
    }

    #[async]
    fn handle_cmd(mut self, cmd: Command) -> Result<Self> {
        println!("Received command: {:?}", cmd);
        match cmd {
            Command::User(content) => {
                if content.is_empty() {
                    self = await!(self.send(Answer::new(ResultCode::InvalidParameterOrArgument,"Invalid username")))?;
                } else {
                    self = await!(self.send(Answer::new(ResultCode::UserloggedIn,&format!("Welcome {}",content))))?;
                }
            },
            Command::Pwd() => {
                let msg = format!("{}", self.cwd.to_str().unwrap_or(""));
                if !msg.is_empty() {
                    let message = format!("\"/{}\" ",msg);
                    //TODO add await
                }
            },
            Command::Unknown(s) => self = await!(self.send(Answer::new(ResultCode::UnknownCommand, &format!("\"{}\": Not Implemented",s))))?,
            _=>  self = await!(self.send(Answer::new(ResultCode::CommandNotImplemented, "Not implemented")))?,
        }
        return Ok(self);
    }

}

#[async]
fn client(stream: TcpStream) -> Result<()>{
    let (writer, reader) = stream.framed(FtpCodec).split();
    let writer = await!(writer.send(Answer::new(ResultCode::ServiceReadyForNewUser, "Welcome to this FTP Server!")))?;
    let mut client = Client::new(writer);
    #[async]
    for cmd in reader {
        client = await!(client.handle_cmd(cmd))?;
    }
    println!("Client closed");
    return Ok(());;
}

#[async]
fn handle_client(stream: TcpStream) -> result::Result<(), ()> {
    await!(client(stream)).map_err(|error| println!("Error handling client: {}", error))
}

#[async]
fn server(handle: Handle) -> io::Result<()> {
    let port = 1234;
    let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127,0,0,1)), port);
    let listener = TcpListener::bind(&addr,&handle)?;
    println!("Waiting clients on port {}...",port);
    #[async]
    for (stream, addr) in listener.incoming() {
        let address = format!("[address : {}]",addr);
        println!("New client {}", address);
        handle.spawn(handle_client(stream));
        println!("Waiting another client...");
    }
    return Ok(());
}

fn main() {
    let mut core = Core::new().expect("Cannot create tokio Core");
    let handle = core.handle();
    if let Err(error) = core.run(server(handle)) {
        println!("Error running the server: {}", error);
    }

}
<commit_msg>Updated main with PWD command<commit_after>#![feature(proc_macro, conservative_impl_trait, generators)]
extern crate bytes;
extern crate futures_await as futures;
extern crate tokio_core;
extern crate tokio_io;

mod cmd;
mod ftp;
mod error;
mod codec;

use std::result;
use std::io;
use futures::prelude::*;
use tokio_core::reactor::Core;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use tokio_core::reactor::Handle;
use tokio_core::net::TcpListener;

use tokio_core::net::TcpStream;

use futures::{Sink, Stream};
use futures::stream::SplitSink;

use tokio_io::AsyncRead;
use tokio_io::codec::Framed;
use codec::FtpCodec;
use error::Result;
use ftp::{Answer, ResultCode};
use std::path::PathBuf;

use cmd::Command;
type Writer = SplitSink<Framed<TcpStream, FtpCodec>>;

struct Client {
    cwd: PathBuf,
    writer: Writer,
}

impl Client {
    fn new(writer: Writer) -> Client {
        Client {
            cwd: PathBuf::from("/"),
            writer,
        }
    }
    #[async]
    fn send(mut self, answer: Answer) -> Result<Self> {
        self.writer = await!(self.writer.send(answer))?;
        Ok(self)
    }

    #[async]
    fn handle_cmd(mut self, cmd: Command) -> Result<Self> {
        println!("Received command: {:?}", cmd);
        match cmd {
            Command::User(content) => {
                if content.is_empty() {
                    self = await!(self.send(Answer::new(ResultCode::InvalidParameterOrArgument,"Invalid username")))?;
                } else {
                    self = await!(self.send(Answer::new(ResultCode::UserloggedIn,&format!("Welcome {}",content))))?;
                }
            },
            Command::Pwd => {
                let msg = format!("{}", self.cwd.to_str().unwrap_or(""));
                if !msg.is_empty() {
                    let message = format!("\"/{}\" ",msg);
                    self = await!(self.send(Answer::new(ResultCode::PATHNAMECreated, &message)))?;
                } else {
                    self = await!(self.send(Answer::new(ResultCode::FileNotFound, "No such file or directory")))?;
                }
            },
            Command::Unknown(s) => self = await!(self.send(Answer::new(ResultCode::UnknownCommand, &format!("\"{}\": Not Implemented",s))))?,
            _=>  self = await!(self.send(Answer::new(ResultCode::CommandNotImplemented, "Not implemented")))?,
        }
        return Ok(self);
    }

}

#[async]
fn client(stream: TcpStream) -> Result<()>{
    let (writer, reader) = stream.framed(FtpCodec).split();
    let writer = await!(writer.send(Answer::new(ResultCode::ServiceReadyForNewUser, "Welcome to this FTP Server!")))?;
    let mut client = Client::new(writer);
    #[async]
    for cmd in reader {
        client = await!(client.handle_cmd(cmd))?;
    }
    println!("Client closed");
    return Ok(());;
}

#[async]
fn handle_client(stream: TcpStream) -> result::Result<(), ()> {
    await!(client(stream)).map_err(|error| println!("Error handling client: {}", error))
}

#[async]
fn server(handle: Handle) -> io::Result<()> {
    let port = 1234;
    let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127,0,0,1)), port);
    let listener = TcpListener::bind(&addr,&handle)?;
    println!("Waiting clients on port {}...",port);
    #[async]
    for (stream, addr) in listener.incoming() {
        let address = format!("[address : {}]",addr);
        println!("New client {}", address);
        handle.spawn(handle_client(stream));
        println!("Waiting another client...");
    }
    return Ok(());
}

fn main() {
    let mut core = Core::new().expect("Cannot create tokio Core");
    let handle = core.handle();
    if let Err(error) = core.run(server(handle)) {
        println!("Error running the server: {}", error);
    }

}
<|endoftext|>