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

// Internal
use clap::*;
use clap_complete::*;

/// Generate fig completion file
pub struct Fig;

impl Generator for Fig {
    fn file_name(&self, name: &str) -> String {
        format!("{}.ts", name)
    }

    fn generate(&self, cmd: &Command, buf: &mut dyn Write) {
        let command = cmd.get_bin_name().unwrap();
        let mut buffer = String::new();

        buffer.push_str(&format!(
            "const completion: Fig.Spec = {{\n  name: \"{}\",\n",
            command
        ));

        buffer.push_str(&format!(
            "  description: \"{}\",\n",
            cmd.get_about().unwrap_or_default()
        ));

        gen_fig_inner(command, &[], 2, cmd, &mut buffer);

        buffer.push_str("};\n\nexport default completion;\n");

        buf.write_all(buffer.as_bytes())
            .expect("Failed to write to generated file");
    }
}

// Escape string inside double quotes
fn escape_string(string: &str) -> String {
    string.replace('\\', "\\\\").replace('\"', "\\\"")
}

fn gen_fig_inner(
    root_command: &str,
    parent_commands: &[&str],
    indent: usize,
    cmd: &Command,
    buffer: &mut String,
) {
    if cmd.has_subcommands() {
        buffer.push_str(&format!("{:indent$}subcommands: [\n", "", indent = indent));
        // generate subcommands
        for subcommand in cmd.get_subcommands() {
            let mut aliases: Vec<&str> = subcommand.get_all_aliases().collect();
            if !aliases.is_empty() {
                aliases.insert(0, subcommand.get_name());

                buffer.push_str(&format!(
                    "{:indent$}{{\n{:indent$}  name: [",
                    "",
                    "",
                    indent = indent + 2
                ));

                buffer.push_str(
                    &aliases
                        .iter()
                        .map(|name| format!("\"{}\"", name))
                        .collect::<Vec<_>>()
                        .join(", "),
                );

                buffer.push_str("],\n");
            } else {
                buffer.push_str(&format!(
                    "{:indent$}{{\n{:indent$}  name: \"{}\",\n",
                    "",
                    "",
                    subcommand.get_name(),
                    indent = indent + 2
                ));
            }

            if let Some(data) = subcommand.get_about() {
                buffer.push_str(&format!(
                    "{:indent$}description: \"{}\",\n",
                    "",
                    escape_string(data),
                    indent = indent + 4
                ));
            }

            if subcommand.is_hide_set() {
                buffer.push_str(&format!(
                    "{:indent$}hidden: true,\n",
                    "",
                    indent = indent + 4
                ))
            }

            let mut parent_commands: Vec<_> = parent_commands.into();
            parent_commands.push(subcommand.get_name());
            gen_fig_inner(
                root_command,
                &parent_commands,
                indent + 4,
                subcommand,
                buffer,
            );

            buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent + 2));
        }
        buffer.push_str(&format!("{:indent$}],\n", "", indent = indent));
    }

    buffer.push_str(&gen_options(cmd, indent));

    let args = cmd.get_positionals().collect::<Vec<_>>();

    match args.len() {
        0 => {}
        1 => {
            buffer.push_str(&format!("{:indent$}args: ", "", indent = indent));

            buffer.push_str(&gen_args(args[0], indent));
        }
        _ => {
            buffer.push_str(&format!("{:indent$}args: [\n", "", indent = indent));
            for arg in args {
                buffer.push_str(&format!("{:indent$}", "", indent = indent + 2));
                buffer.push_str(&gen_args(arg, indent + 2));
            }
            buffer.push_str(&format!("{:indent$}]\n", "", indent = indent));
        }
    };
}

fn gen_options(cmd: &Command, indent: usize) -> String {
    let mut buffer = String::new();

    let flags = generator::utils::flags(cmd);

    if cmd.get_opts().next().is_some() || !flags.is_empty() {
        buffer.push_str(&format!("{:indent$}options: [\n", "", indent = indent));

        for option in cmd.get_opts() {
            buffer.push_str(&format!("{:indent$}{{\n", "", indent = indent + 2));

            let mut names = vec![];

            if let Some(shorts) = option.get_short_and_visible_aliases() {
                names.extend(shorts.iter().map(|short| format!("-{}", short)));
            }

            if let Some(longs) = option.get_long_and_visible_aliases() {
                names.extend(longs.iter().map(|long| format!("--{}", long)));
            }

            if names.len() > 1 {
                buffer.push_str(&format!("{:indent$}name: [", "", indent = indent + 4));

                buffer.push_str(
                    &names
                        .iter()
                        .map(|name| format!("\"{}\"", name))
                        .collect::<Vec<_>>()
                        .join(", "),
                );

                buffer.push_str("],\n");
            } else {
                buffer.push_str(&format!(
                    "{:indent$}name: \"{}\",\n",
                    "",
                    names[0],
                    indent = indent + 4
                ));
            }

            if let Some(data) = option.get_help() {
                buffer.push_str(&format!(
                    "{:indent$}description: \"{}\",\n",
                    "",
                    escape_string(data),
                    indent = indent + 4
                ));
            }

            if option.is_hide_set() {
                buffer.push_str(&format!(
                    "{:indent$}hidden: true,\n",
                    "",
                    indent = indent + 4
                ))
            }

            let conflicts = arg_conflicts(cmd, option);

            if !conflicts.is_empty() {
                buffer.push_str(&format!(
                    "{:indent$}exclusiveOn: [\n",
                    "",
                    indent = indent + 4
                ));

                for conflict in conflicts {
                    buffer.push_str(&format!(
                        "{:indent$}\"{}\",\n",
                        "",
                        conflict,
                        indent = indent + 6
                    ));
                }

                buffer.push_str(&format!("{:indent$}],\n", "", indent = indent + 4));
            }

            if let ArgAction::Set | ArgAction::Append | ArgAction::Count =
                option.get_action()
            {
                buffer.push_str(&format!(
                    "{:indent$}isRepeatable: true,\n",
                    "",
                    indent = indent + 4
                ));
            }

            if option.is_require_equals_set() {
                buffer.push_str(&format!(
                    "{:indent$}requiresEquals: true,\n",
                    "",
                    indent = indent + 4
                ));
            }

            buffer.push_str(&format!("{:indent$}args: ", "", indent = indent + 4));

            buffer.push_str(&gen_args(option, indent + 4));

            buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent + 2));
        }

        for flag in generator::utils::flags(cmd) {
            buffer.push_str(&format!("{:indent$}{{\n", "", indent = indent + 2));

            let mut flags = vec![];

            if let Some(shorts) = flag.get_short_and_visible_aliases() {
                flags.extend(shorts.iter().map(|s| format!("-{}", s)));
            }

            if let Some(longs) = flag.get_long_and_visible_aliases() {
                flags.extend(longs.iter().map(|s| format!("--{}", s)));
            }

            if flags.len() > 1 {
                buffer.push_str(&format!("{:indent$}name: [", "", indent = indent + 4));

                buffer.push_str(
                    &flags
                        .iter()
                        .map(|name| format!("\"{}\"", name))
                        .collect::<Vec<_>>()
                        .join(", "),
                );

                buffer.push_str("],\n");
            } else {
                buffer.push_str(&format!(
                    "{:indent$}name: \"{}\",\n",
                    "",
                    flags[0],
                    indent = indent + 4
                ));
            }

            if let Some(data) = flag.get_help() {
                buffer.push_str(&format!(
                    "{:indent$}description: \"{}\",\n",
                    "",
                    escape_string(data).as_str(),
                    indent = indent + 4
                ));
            }

            let conflicts = arg_conflicts(cmd, &flag);

            if !conflicts.is_empty() {
                buffer.push_str(&format!(
                    "{:indent$}exclusiveOn: [\n",
                    "",
                    indent = indent + 4
                ));

                for conflict in conflicts {
                    buffer.push_str(&format!(
                        "{:indent$}\"{}\",\n",
                        "",
                        conflict,
                        indent = indent + 6
                    ));
                }

                buffer.push_str(&format!("{:indent$}],\n", "", indent = indent + 4));
            }

            if let ArgAction::Set | ArgAction::Append | ArgAction::Count =
                flag.get_action()
            {
                buffer.push_str(&format!(
                    "{:indent$}isRepeatable: true,\n",
                    "",
                    indent = indent + 4
                ));
            }

            buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent + 2));
        }

        buffer.push_str(&format!("{:indent$}],\n", "", indent = indent));
    }

    buffer
}

fn gen_args(arg: &Arg, indent: usize) -> String {
    if !arg.is_takes_value_set() {
        return "".to_string();
    }

    let mut buffer = String::new();

    buffer.push_str(&format!(
        "{{\n{:indent$}  name: \"{}\",\n",
        "",
        arg.get_id(),
        indent = indent
    ));

    if arg.is_multiple_values_set() {
        buffer.push_str(&format!(
            "{:indent$}isVariadic: true,\n",
            "",
            indent = indent + 2
        ));
    }

    if !arg.is_required_set() {
        buffer.push_str(&format!(
            "{:indent$}isOptional: true,\n",
            "",
            indent = indent + 2
        ));
    }

    if let Some(data) = generator::utils::possible_values(arg) {
        buffer.push_str(&format!(
            "{:indent$}suggestions: [\n",
            "",
            indent = indent + 2
        ));

        for value in data {
            if let Some(help) = value.get_help() {
                buffer.push_str(&format!(
                    "{:indent$}{{\n{:indent$}  name: \"{}\",\n",
                    "",
                    "",
                    value.get_name(),
                    indent = indent + 4,
                ));

                buffer.push_str(&format!(
                    "{:indent$}description: \"{}\",\n",
                    "",
                    escape_string(help),
                    indent = indent + 6
                ));

                buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent + 4));
            } else {
                buffer.push_str(&format!(
                    "{:indent$}\"{}\",\n",
                    "",
                    value.get_name(),
                    indent = indent + 4,
                ));
            }
        }

        buffer.push_str(&format!("{:indent$}],\n", "", indent = indent + 2));
    } else {
        match arg.get_value_hint() {
            ValueHint::AnyPath | ValueHint::FilePath | ValueHint::ExecutablePath => {
                buffer.push_str(&format!(
                    "{:indent$}template: \"filepaths\",\n",
                    "",
                    indent = indent + 2
                ));
            }
            ValueHint::DirPath => {
                buffer.push_str(&format!(
                    "{:indent$}template: \"folders\",\n",
                    "",
                    indent = indent + 2
                ));
            }
            ValueHint::CommandString | ValueHint::CommandName | ValueHint::CommandWithArguments => {
                buffer.push_str(&format!(
                    "{:indent$}isCommand: true,\n",
                    "",
                    indent = indent + 2
                ));
            }
            // Disable completion for others
            _ => (),
        };
    };

    buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent));

    buffer
}

fn arg_conflicts(cmd: &Command, arg: &Arg) -> Vec<String> {
    let mut res = vec![];

    for conflict in cmd.get_arg_conflicts_with(arg) {
        if let Some(s) = conflict.get_short() {
            res.push(format!("-{}", s));
        }

        if let Some(l) = conflict.get_long() {
            res.push(format!("--{}", l));
        }
    }

    res
}
<commit_msg>fix: Run cargo fmt<commit_after>// Std
use std::io::Write;

// Internal
use clap::*;
use clap_complete::*;

/// Generate fig completion file
pub struct Fig;

impl Generator for Fig {
    fn file_name(&self, name: &str) -> String {
        format!("{}.ts", name)
    }

    fn generate(&self, cmd: &Command, buf: &mut dyn Write) {
        let command = cmd.get_bin_name().unwrap();
        let mut buffer = String::new();

        buffer.push_str(&format!(
            "const completion: Fig.Spec = {{\n  name: \"{}\",\n",
            command
        ));

        buffer.push_str(&format!(
            "  description: \"{}\",\n",
            cmd.get_about().unwrap_or_default()
        ));

        gen_fig_inner(command, &[], 2, cmd, &mut buffer);

        buffer.push_str("};\n\nexport default completion;\n");

        buf.write_all(buffer.as_bytes())
            .expect("Failed to write to generated file");
    }
}

// Escape string inside double quotes
fn escape_string(string: &str) -> String {
    string.replace('\\', "\\\\").replace('\"', "\\\"")
}

fn gen_fig_inner(
    root_command: &str,
    parent_commands: &[&str],
    indent: usize,
    cmd: &Command,
    buffer: &mut String,
) {
    if cmd.has_subcommands() {
        buffer.push_str(&format!("{:indent$}subcommands: [\n", "", indent = indent));
        // generate subcommands
        for subcommand in cmd.get_subcommands() {
            let mut aliases: Vec<&str> = subcommand.get_all_aliases().collect();
            if !aliases.is_empty() {
                aliases.insert(0, subcommand.get_name());

                buffer.push_str(&format!(
                    "{:indent$}{{\n{:indent$}  name: [",
                    "",
                    "",
                    indent = indent + 2
                ));

                buffer.push_str(
                    &aliases
                        .iter()
                        .map(|name| format!("\"{}\"", name))
                        .collect::<Vec<_>>()
                        .join(", "),
                );

                buffer.push_str("],\n");
            } else {
                buffer.push_str(&format!(
                    "{:indent$}{{\n{:indent$}  name: \"{}\",\n",
                    "",
                    "",
                    subcommand.get_name(),
                    indent = indent + 2
                ));
            }

            if let Some(data) = subcommand.get_about() {
                buffer.push_str(&format!(
                    "{:indent$}description: \"{}\",\n",
                    "",
                    escape_string(data),
                    indent = indent + 4
                ));
            }

            if subcommand.is_hide_set() {
                buffer.push_str(&format!(
                    "{:indent$}hidden: true,\n",
                    "",
                    indent = indent + 4
                ))
            }

            let mut parent_commands: Vec<_> = parent_commands.into();
            parent_commands.push(subcommand.get_name());
            gen_fig_inner(
                root_command,
                &parent_commands,
                indent + 4,
                subcommand,
                buffer,
            );

            buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent + 2));
        }
        buffer.push_str(&format!("{:indent$}],\n", "", indent = indent));
    }

    buffer.push_str(&gen_options(cmd, indent));

    let args = cmd.get_positionals().collect::<Vec<_>>();

    match args.len() {
        0 => {}
        1 => {
            buffer.push_str(&format!("{:indent$}args: ", "", indent = indent));

            buffer.push_str(&gen_args(args[0], indent));
        }
        _ => {
            buffer.push_str(&format!("{:indent$}args: [\n", "", indent = indent));
            for arg in args {
                buffer.push_str(&format!("{:indent$}", "", indent = indent + 2));
                buffer.push_str(&gen_args(arg, indent + 2));
            }
            buffer.push_str(&format!("{:indent$}]\n", "", indent = indent));
        }
    };
}

fn gen_options(cmd: &Command, indent: usize) -> String {
    let mut buffer = String::new();

    let flags = generator::utils::flags(cmd);

    if cmd.get_opts().next().is_some() || !flags.is_empty() {
        buffer.push_str(&format!("{:indent$}options: [\n", "", indent = indent));

        for option in cmd.get_opts() {
            buffer.push_str(&format!("{:indent$}{{\n", "", indent = indent + 2));

            let mut names = vec![];

            if let Some(shorts) = option.get_short_and_visible_aliases() {
                names.extend(shorts.iter().map(|short| format!("-{}", short)));
            }

            if let Some(longs) = option.get_long_and_visible_aliases() {
                names.extend(longs.iter().map(|long| format!("--{}", long)));
            }

            if names.len() > 1 {
                buffer.push_str(&format!("{:indent$}name: [", "", indent = indent + 4));

                buffer.push_str(
                    &names
                        .iter()
                        .map(|name| format!("\"{}\"", name))
                        .collect::<Vec<_>>()
                        .join(", "),
                );

                buffer.push_str("],\n");
            } else {
                buffer.push_str(&format!(
                    "{:indent$}name: \"{}\",\n",
                    "",
                    names[0],
                    indent = indent + 4
                ));
            }

            if let Some(data) = option.get_help() {
                buffer.push_str(&format!(
                    "{:indent$}description: \"{}\",\n",
                    "",
                    escape_string(data),
                    indent = indent + 4
                ));
            }

            if option.is_hide_set() {
                buffer.push_str(&format!(
                    "{:indent$}hidden: true,\n",
                    "",
                    indent = indent + 4
                ))
            }

            let conflicts = arg_conflicts(cmd, option);

            if !conflicts.is_empty() {
                buffer.push_str(&format!(
                    "{:indent$}exclusiveOn: [\n",
                    "",
                    indent = indent + 4
                ));

                for conflict in conflicts {
                    buffer.push_str(&format!(
                        "{:indent$}\"{}\",\n",
                        "",
                        conflict,
                        indent = indent + 6
                    ));
                }

                buffer.push_str(&format!("{:indent$}],\n", "", indent = indent + 4));
            }

            if let ArgAction::Set | ArgAction::Append | ArgAction::Count = option.get_action() {
                buffer.push_str(&format!(
                    "{:indent$}isRepeatable: true,\n",
                    "",
                    indent = indent + 4
                ));
            }

            if option.is_require_equals_set() {
                buffer.push_str(&format!(
                    "{:indent$}requiresEquals: true,\n",
                    "",
                    indent = indent + 4
                ));
            }

            buffer.push_str(&format!("{:indent$}args: ", "", indent = indent + 4));

            buffer.push_str(&gen_args(option, indent + 4));

            buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent + 2));
        }

        for flag in generator::utils::flags(cmd) {
            buffer.push_str(&format!("{:indent$}{{\n", "", indent = indent + 2));

            let mut flags = vec![];

            if let Some(shorts) = flag.get_short_and_visible_aliases() {
                flags.extend(shorts.iter().map(|s| format!("-{}", s)));
            }

            if let Some(longs) = flag.get_long_and_visible_aliases() {
                flags.extend(longs.iter().map(|s| format!("--{}", s)));
            }

            if flags.len() > 1 {
                buffer.push_str(&format!("{:indent$}name: [", "", indent = indent + 4));

                buffer.push_str(
                    &flags
                        .iter()
                        .map(|name| format!("\"{}\"", name))
                        .collect::<Vec<_>>()
                        .join(", "),
                );

                buffer.push_str("],\n");
            } else {
                buffer.push_str(&format!(
                    "{:indent$}name: \"{}\",\n",
                    "",
                    flags[0],
                    indent = indent + 4
                ));
            }

            if let Some(data) = flag.get_help() {
                buffer.push_str(&format!(
                    "{:indent$}description: \"{}\",\n",
                    "",
                    escape_string(data).as_str(),
                    indent = indent + 4
                ));
            }

            let conflicts = arg_conflicts(cmd, &flag);

            if !conflicts.is_empty() {
                buffer.push_str(&format!(
                    "{:indent$}exclusiveOn: [\n",
                    "",
                    indent = indent + 4
                ));

                for conflict in conflicts {
                    buffer.push_str(&format!(
                        "{:indent$}\"{}\",\n",
                        "",
                        conflict,
                        indent = indent + 6
                    ));
                }

                buffer.push_str(&format!("{:indent$}],\n", "", indent = indent + 4));
            }

            if let ArgAction::Set | ArgAction::Append | ArgAction::Count = flag.get_action() {
                buffer.push_str(&format!(
                    "{:indent$}isRepeatable: true,\n",
                    "",
                    indent = indent + 4
                ));
            }

            buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent + 2));
        }

        buffer.push_str(&format!("{:indent$}],\n", "", indent = indent));
    }

    buffer
}

fn gen_args(arg: &Arg, indent: usize) -> String {
    if !arg.is_takes_value_set() {
        return "".to_string();
    }

    let mut buffer = String::new();

    buffer.push_str(&format!(
        "{{\n{:indent$}  name: \"{}\",\n",
        "",
        arg.get_id(),
        indent = indent
    ));

    if arg.is_multiple_values_set() {
        buffer.push_str(&format!(
            "{:indent$}isVariadic: true,\n",
            "",
            indent = indent + 2
        ));
    }

    if !arg.is_required_set() {
        buffer.push_str(&format!(
            "{:indent$}isOptional: true,\n",
            "",
            indent = indent + 2
        ));
    }

    if let Some(data) = generator::utils::possible_values(arg) {
        buffer.push_str(&format!(
            "{:indent$}suggestions: [\n",
            "",
            indent = indent + 2
        ));

        for value in data {
            if let Some(help) = value.get_help() {
                buffer.push_str(&format!(
                    "{:indent$}{{\n{:indent$}  name: \"{}\",\n",
                    "",
                    "",
                    value.get_name(),
                    indent = indent + 4,
                ));

                buffer.push_str(&format!(
                    "{:indent$}description: \"{}\",\n",
                    "",
                    escape_string(help),
                    indent = indent + 6
                ));

                buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent + 4));
            } else {
                buffer.push_str(&format!(
                    "{:indent$}\"{}\",\n",
                    "",
                    value.get_name(),
                    indent = indent + 4,
                ));
            }
        }

        buffer.push_str(&format!("{:indent$}],\n", "", indent = indent + 2));
    } else {
        match arg.get_value_hint() {
            ValueHint::AnyPath | ValueHint::FilePath | ValueHint::ExecutablePath => {
                buffer.push_str(&format!(
                    "{:indent$}template: \"filepaths\",\n",
                    "",
                    indent = indent + 2
                ));
            }
            ValueHint::DirPath => {
                buffer.push_str(&format!(
                    "{:indent$}template: \"folders\",\n",
                    "",
                    indent = indent + 2
                ));
            }
            ValueHint::CommandString | ValueHint::CommandName | ValueHint::CommandWithArguments => {
                buffer.push_str(&format!(
                    "{:indent$}isCommand: true,\n",
                    "",
                    indent = indent + 2
                ));
            }
            // Disable completion for others
            _ => (),
        };
    };

    buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent));

    buffer
}

fn arg_conflicts(cmd: &Command, arg: &Arg) -> Vec<String> {
    let mut res = vec![];

    for conflict in cmd.get_arg_conflicts_with(arg) {
        if let Some(s) = conflict.get_short() {
            res.push(format!("-{}", s));
        }

        if let Some(l) = conflict.get_long() {
            res.push(format!("--{}", l));
        }
    }

    res
}
<|endoftext|>


<commit_before>use crate::codec::*;
use crate::error::*;
use crate::fair_queue::FairQueue;
use crate::*;
use crate::{SocketType, ZmqResult};
use async_trait::async_trait;
use crossbeam::atomic::AtomicCell;
use crossbeam::queue::SegQueue;
use dashmap::DashMap;
use futures::lock::Mutex;
use futures::stream::FuturesUnordered;
use futures_util::sink::SinkExt;
use std::sync::Arc;
use std::time::Duration;
use tokio::stream::StreamExt;

struct ReqSocketBackend {
    pub(crate) peers: DashMap<PeerIdentity, Peer>,
    pub(crate) round_robin: SegQueue<PeerIdentity>,
    pub(crate) current_request_peer_id: Mutex<Option<PeerIdentity>>,
}

pub struct ReqSocket {
    backend: Arc<ReqSocketBackend>,
    _accept_close_handle: Option<oneshot::Sender<bool>>,
    current_request: Option<PeerIdentity>,
}

#[async_trait]
impl BlockingSend for ReqSocket {
    async fn send(&mut self, message: ZmqMessage) -> ZmqResult<()> {
        if self.current_request.is_some() {
            return Err(ZmqError::Socket(
                "Unable to send message. Request already in progress",
            ));
        }
        // In normal scenario this will always be only 1 iteration
        // There can be special case when peer has disconnected and his id is still in RR queue
        // This happens because SegQueue don't have an api to delete items from queue.
        // So in such case we'll just pop item and skip it if we don't have a matching peer in peers map
        loop {
            let next_peer_id = match self.backend.round_robin.pop() {
                Ok(peer) => peer,
                Err(_) => {
                    return Err(ZmqError::Other(
                        "Not connected to peers. Unable to send messages",
                    ))
                }
            };
            match self.backend.peers.get_mut(&next_peer_id) {
                Some(mut peer) => {
                    self.backend.round_robin.push(next_peer_id.clone());
                    let frames = vec![
                        "".into(), // delimiter frame
                        message,
                    ];
                    peer.send_queue
                        .send(Message::MultipartMessage(frames))
                        .await?;
                    self.backend
                        .current_request_peer_id
                        .lock()
                        .await
                        .replace(next_peer_id.clone());
                    self.current_request = Some(next_peer_id);
                    return Ok(());
                }
                None => continue,
            }
        }
    }
}

#[async_trait]
impl BlockingRecv for ReqSocket {
    async fn recv(&mut self) -> ZmqResult<ZmqMessage> {
        match self.current_request.take() {
            Some(peer_id) => {
                if let Some(recv_queue) = self
                    .backend
                    .peers
                    .get(&peer_id)
                    .map(|p| p.recv_queue.clone())
                {
                    let message = recv_queue.lock().await.next().await;
                    match message {
                        Some(Message::MultipartMessage(mut message)) => {
                            assert!(message.len() == 2);
                            assert!(message[0].data.is_empty()); // Ensure that we have delimeter as first part
                            Ok(message.pop().unwrap())
                        }
                        Some(_) => Err(ZmqError::Other("Wrong message type received")),
                        None => Err(ZmqError::NoMessage),
                    }
                } else {
                    Err(ZmqError::Other("Server disconnected"))
                }
            }
            None => Err(ZmqError::Other("Unable to recv. No request in progress")),
        }
    }
}

#[async_trait]
impl SocketFrontend for ReqSocket {
    fn new() -> Self {
        Self {
            backend: Arc::new(ReqSocketBackend {
                peers: DashMap::new(),
                round_robin: SegQueue::new(),
                current_request_peer_id: Mutex::new(None),
            }),
            _accept_close_handle: None,
            current_request: None,
        }
    }

    async fn bind(&mut self, endpoint: &str) -> ZmqResult<()> {
        if self._accept_close_handle.is_some() {
            return Err(ZmqError::Other(
                "Socket server already started. Currently only one server is supported",
            ));
        }
        let stop_handle = util::start_accepting_connections(endpoint, self.backend.clone()).await?;
        self._accept_close_handle = Some(stop_handle);
        Ok(())
    }

    async fn connect(&mut self, endpoint: &str) -> ZmqResult<()> {
        let addr = endpoint.parse::<SocketAddr>()?;
        let raw_socket = tokio::net::TcpStream::connect(addr).await?;
        util::peer_connected(raw_socket, self.backend.clone()).await;
        Ok(())
    }
}

#[async_trait]
impl MultiPeer for ReqSocketBackend {
    async fn peer_connected(
        &self,
        peer_id: &PeerIdentity,
    ) -> (mpsc::Receiver<Message>, oneshot::Receiver<bool>) {
        let default_queue_size = 1;
        let (out_queue, out_queue_receiver) = mpsc::channel(default_queue_size);
        let (in_queue, in_queue_receiver) = mpsc::channel(default_queue_size);
        let (stop_handle, stop_callback) = oneshot::channel::<bool>();

        self.peers.insert(
            peer_id.clone(),
            Peer {
                identity: peer_id.clone(),
                send_queue: out_queue,
                recv_queue: Arc::new(Mutex::new(in_queue_receiver)),
                recv_queue_in: in_queue,
                _io_close_handle: stop_handle,
            },
        );
        self.round_robin.push(peer_id.clone());

        (out_queue_receiver, stop_callback)
    }

    async fn peer_disconnected(&self, peer_id: &PeerIdentity) {
        self.peers.remove(peer_id);
    }
}

#[async_trait]
impl SocketBackend for ReqSocketBackend {
    async fn message_received(&self, peer_id: &PeerIdentity, message: Message) {
        // This is needed to ensure that we only store messages that we are expecting to get
        // Other messages are silently discarded according to spec
        let mut curr_req_lock = self.current_request_peer_id.lock().await;
        match curr_req_lock.take() {
            Some(id) => {
                if &id != peer_id {
                    curr_req_lock.replace(id);
                    return;
                }
            }
            None => return,
        }
        drop(curr_req_lock);
        // We've got reply that we were waiting for
        self.peers
            .get_mut(peer_id)
            .expect("Not found peer by id")
            .recv_queue_in
            .send(message)
            .await
            .expect("Failed to send");
    }

    fn socket_type(&self) -> SocketType {
        SocketType::REQ
    }

    fn shutdown(&self) {
        self.peers.clear();
    }
}

struct RepPeer {
    pub(crate) identity: PeerIdentity,
    pub(crate) send_queue: mpsc::Sender<Message>,
    pub(crate) recv_queue_in: mpsc::Sender<Message>,
    pub(crate) _io_close_handle: futures::channel::oneshot::Sender<bool>,
}

struct FairQueueProcessor {
    pub(crate) fair_queue_stream: FairQueue<mpsc::Receiver<Message>, PeerIdentity>,
    pub(crate) socket_incoming_queue: mpsc::Sender<(PeerIdentity, Message)>,
    pub(crate) peer_queue_in:
        mpsc::Receiver<(PeerIdentity, mpsc::Receiver<Message>)>,
}

struct RepSocketBackend {
    pub(crate) peers: Arc<DashMap<PeerIdentity, RepPeer>>,
    pub(crate) processor: Mutex<FairQueueProcessor>,
    pub(crate) peer_queue_in: mpsc::Sender<(PeerIdentity, mpsc::Receiver<Message>)>,
}

pub struct RepSocket {
    backend: Arc<RepSocketBackend>,
    _accept_close_handle: Option<oneshot::Sender<bool>>,
    current_request: Option<PeerIdentity>,
    fair_queue: mpsc::Receiver<(PeerIdentity, Message)>,
}

#[async_trait]
impl SocketFrontend for RepSocket {
    fn new() -> Self {
        // TODO define buffer size
        let default_queue_size = 100;
        let (queue_sender, fair_queue) = mpsc::channel(default_queue_size);
        let (peer_in, peer_out) = mpsc::channel(default_queue_size);
        Self {
            backend: Arc::new(RepSocketBackend {
                peers: Arc::new(DashMap::new()),
                processor: Mutex::new(FairQueueProcessor {
                    fair_queue_stream: FairQueue::new(),
                    socket_incoming_queue: queue_sender,
                    peer_queue_in: peer_out,
                }),
                peer_queue_in: peer_in,
            }),
            _accept_close_handle: None,
            current_request: None,
            fair_queue,
        }
    }

    async fn bind(&mut self, endpoint: &str) -> ZmqResult<()> {
        let stop_handle = util::start_accepting_connections(endpoint, self.backend.clone()).await?;
        self._accept_close_handle = Some(stop_handle);
        Ok(())
    }

    async fn connect(&mut self, endpoint: &str) -> ZmqResult<()> {
        unimplemented!()
    }
}

#[async_trait]
impl MultiPeer for RepSocketBackend {
    async fn peer_connected(
        &self,
        peer_id: &PeerIdentity,
    ) -> (mpsc::Receiver<Message>, oneshot::Receiver<bool>) {
        let default_queue_size = 100;
        let (out_queue, out_queue_receiver) = mpsc::channel(default_queue_size);
        let (in_queue, in_queue_receiver) = mpsc::channel::<Message>(default_queue_size);
        let (stop_handle, stop_callback) = oneshot::channel::<bool>();

        self.peers.insert(
            peer_id.clone(),
            RepPeer {
                identity: peer_id.clone(),
                send_queue: out_queue,
                recv_queue_in: in_queue,
                _io_close_handle: stop_handle,
            },
        );
        self.peer_queue_in.clone().try_send(
            (peer_id.clone(), in_queue_receiver)
        ).unwrap();

        (out_queue_receiver, stop_callback)
    }

    async fn peer_disconnected(&self, peer_id: &PeerIdentity) {
        self.peers.remove(peer_id);
    }
}

#[async_trait]
impl SocketBackend for RepSocketBackend {
    async fn message_received(&self, peer_id: &PeerIdentity, message: Message) {
        self.peers
            .get_mut(peer_id)
            .expect("Not found peer by id")
            .recv_queue_in
            .send(message)
            .await
            .expect("Failed to send");
    }

    fn socket_type(&self) -> SocketType {
        SocketType::REP
    }

    fn shutdown(&self) {
        self.peers.clear();
    }
}

#[async_trait]
impl BlockingSend for RepSocket {
    async fn send(&mut self, message: ZmqMessage) -> ZmqResult<()> {
        match self.current_request.take() {
            Some(peer_id) => {
                if let Some(mut peer) = self.backend.peers.get_mut(&peer_id) {
                    let frames = vec![
                        "".into(), // delimiter frame
                        message,
                    ];
                    peer.send_queue
                        .send(Message::MultipartMessage(frames))
                        .await?;
                    Ok(())
                } else {
                    Err(ZmqError::Other("Client disconnected"))
                }
            }
            None => Err(ZmqError::Other(
                "Unable to send reply. No request in progress",
            )),
        }
    }
}

#[async_trait]
impl BlockingRecv for RepSocket {
    async fn recv(&mut self) -> ZmqResult<ZmqMessage> {
        loop {
            match self.fair_queue.next().await {
                Some((peer_id, Message::MultipartMessage(mut messages))) => {
                    assert!(messages.len() == 2);
                    assert!(messages[0].data.is_empty()); // Ensure that we have delimeter as first part
                    self.current_request = Some(peer_id);
                    return Ok(messages.pop().unwrap());
                }
                Some((_peer_id, _)) => todo!(),
                None => todo!(),
            };
        }
    }
}
<commit_msg>Removed useless arc<commit_after>use crate::codec::*;
use crate::error::*;
use crate::fair_queue::FairQueue;
use crate::*;
use crate::{SocketType, ZmqResult};
use async_trait::async_trait;
use crossbeam::atomic::AtomicCell;
use crossbeam::queue::SegQueue;
use dashmap::DashMap;
use futures::lock::Mutex;
use futures::stream::FuturesUnordered;
use futures_util::sink::SinkExt;
use std::sync::Arc;
use std::time::Duration;
use tokio::stream::StreamExt;

struct ReqSocketBackend {
    pub(crate) peers: DashMap<PeerIdentity, Peer>,
    pub(crate) round_robin: SegQueue<PeerIdentity>,
    pub(crate) current_request_peer_id: Mutex<Option<PeerIdentity>>,
}

pub struct ReqSocket {
    backend: Arc<ReqSocketBackend>,
    _accept_close_handle: Option<oneshot::Sender<bool>>,
    current_request: Option<PeerIdentity>,
}

#[async_trait]
impl BlockingSend for ReqSocket {
    async fn send(&mut self, message: ZmqMessage) -> ZmqResult<()> {
        if self.current_request.is_some() {
            return Err(ZmqError::Socket(
                "Unable to send message. Request already in progress",
            ));
        }
        // In normal scenario this will always be only 1 iteration
        // There can be special case when peer has disconnected and his id is still in RR queue
        // This happens because SegQueue don't have an api to delete items from queue.
        // So in such case we'll just pop item and skip it if we don't have a matching peer in peers map
        loop {
            let next_peer_id = match self.backend.round_robin.pop() {
                Ok(peer) => peer,
                Err(_) => {
                    return Err(ZmqError::Other(
                        "Not connected to peers. Unable to send messages",
                    ))
                }
            };
            match self.backend.peers.get_mut(&next_peer_id) {
                Some(mut peer) => {
                    self.backend.round_robin.push(next_peer_id.clone());
                    let frames = vec![
                        "".into(), // delimiter frame
                        message,
                    ];
                    peer.send_queue
                        .send(Message::MultipartMessage(frames))
                        .await?;
                    self.backend
                        .current_request_peer_id
                        .lock()
                        .await
                        .replace(next_peer_id.clone());
                    self.current_request = Some(next_peer_id);
                    return Ok(());
                }
                None => continue,
            }
        }
    }
}

#[async_trait]
impl BlockingRecv for ReqSocket {
    async fn recv(&mut self) -> ZmqResult<ZmqMessage> {
        match self.current_request.take() {
            Some(peer_id) => {
                if let Some(recv_queue) = self
                    .backend
                    .peers
                    .get(&peer_id)
                    .map(|p| p.recv_queue.clone())
                {
                    let message = recv_queue.lock().await.next().await;
                    match message {
                        Some(Message::MultipartMessage(mut message)) => {
                            assert!(message.len() == 2);
                            assert!(message[0].data.is_empty()); // Ensure that we have delimeter as first part
                            Ok(message.pop().unwrap())
                        }
                        Some(_) => Err(ZmqError::Other("Wrong message type received")),
                        None => Err(ZmqError::NoMessage),
                    }
                } else {
                    Err(ZmqError::Other("Server disconnected"))
                }
            }
            None => Err(ZmqError::Other("Unable to recv. No request in progress")),
        }
    }
}

#[async_trait]
impl SocketFrontend for ReqSocket {
    fn new() -> Self {
        Self {
            backend: Arc::new(ReqSocketBackend {
                peers: DashMap::new(),
                round_robin: SegQueue::new(),
                current_request_peer_id: Mutex::new(None),
            }),
            _accept_close_handle: None,
            current_request: None,
        }
    }

    async fn bind(&mut self, endpoint: &str) -> ZmqResult<()> {
        if self._accept_close_handle.is_some() {
            return Err(ZmqError::Other(
                "Socket server already started. Currently only one server is supported",
            ));
        }
        let stop_handle = util::start_accepting_connections(endpoint, self.backend.clone()).await?;
        self._accept_close_handle = Some(stop_handle);
        Ok(())
    }

    async fn connect(&mut self, endpoint: &str) -> ZmqResult<()> {
        let addr = endpoint.parse::<SocketAddr>()?;
        let raw_socket = tokio::net::TcpStream::connect(addr).await?;
        util::peer_connected(raw_socket, self.backend.clone()).await;
        Ok(())
    }
}

#[async_trait]
impl MultiPeer for ReqSocketBackend {
    async fn peer_connected(
        &self,
        peer_id: &PeerIdentity,
    ) -> (mpsc::Receiver<Message>, oneshot::Receiver<bool>) {
        let default_queue_size = 1;
        let (out_queue, out_queue_receiver) = mpsc::channel(default_queue_size);
        let (in_queue, in_queue_receiver) = mpsc::channel(default_queue_size);
        let (stop_handle, stop_callback) = oneshot::channel::<bool>();

        self.peers.insert(
            peer_id.clone(),
            Peer {
                identity: peer_id.clone(),
                send_queue: out_queue,
                recv_queue: Arc::new(Mutex::new(in_queue_receiver)),
                recv_queue_in: in_queue,
                _io_close_handle: stop_handle,
            },
        );
        self.round_robin.push(peer_id.clone());

        (out_queue_receiver, stop_callback)
    }

    async fn peer_disconnected(&self, peer_id: &PeerIdentity) {
        self.peers.remove(peer_id);
    }
}

#[async_trait]
impl SocketBackend for ReqSocketBackend {
    async fn message_received(&self, peer_id: &PeerIdentity, message: Message) {
        // This is needed to ensure that we only store messages that we are expecting to get
        // Other messages are silently discarded according to spec
        let mut curr_req_lock = self.current_request_peer_id.lock().await;
        match curr_req_lock.take() {
            Some(id) => {
                if &id != peer_id {
                    curr_req_lock.replace(id);
                    return;
                }
            }
            None => return,
        }
        drop(curr_req_lock);
        // We've got reply that we were waiting for
        self.peers
            .get_mut(peer_id)
            .expect("Not found peer by id")
            .recv_queue_in
            .send(message)
            .await
            .expect("Failed to send");
    }

    fn socket_type(&self) -> SocketType {
        SocketType::REQ
    }

    fn shutdown(&self) {
        self.peers.clear();
    }
}

struct RepPeer {
    pub(crate) identity: PeerIdentity,
    pub(crate) send_queue: mpsc::Sender<Message>,
    pub(crate) recv_queue_in: mpsc::Sender<Message>,
    pub(crate) _io_close_handle: futures::channel::oneshot::Sender<bool>,
}

struct FairQueueProcessor {
    pub(crate) fair_queue_stream: FairQueue<mpsc::Receiver<Message>, PeerIdentity>,
    pub(crate) socket_incoming_queue: mpsc::Sender<(PeerIdentity, Message)>,
    pub(crate) peer_queue_in:
        mpsc::Receiver<(PeerIdentity, mpsc::Receiver<Message>)>,
}

struct RepSocketBackend {
    pub(crate) peers: DashMap<PeerIdentity, RepPeer>,
    pub(crate) processor: Mutex<FairQueueProcessor>,
    pub(crate) peer_queue_in: mpsc::Sender<(PeerIdentity, mpsc::Receiver<Message>)>,
}

pub struct RepSocket {
    backend: Arc<RepSocketBackend>,
    _accept_close_handle: Option<oneshot::Sender<bool>>,
    current_request: Option<PeerIdentity>,
    fair_queue: mpsc::Receiver<(PeerIdentity, Message)>,
}

#[async_trait]
impl SocketFrontend for RepSocket {
    fn new() -> Self {
        // TODO define buffer size
        let default_queue_size = 100;
        let (queue_sender, fair_queue) = mpsc::channel(default_queue_size);
        let (peer_in, peer_out) = mpsc::channel(default_queue_size);
        Self {
            backend: Arc::new(RepSocketBackend {
                peers: DashMap::new(),
                processor: Mutex::new(FairQueueProcessor {
                    fair_queue_stream: FairQueue::new(),
                    socket_incoming_queue: queue_sender,
                    peer_queue_in: peer_out,
                }),
                peer_queue_in: peer_in,
            }),
            _accept_close_handle: None,
            current_request: None,
            fair_queue,
        }
    }

    async fn bind(&mut self, endpoint: &str) -> ZmqResult<()> {
        let stop_handle = util::start_accepting_connections(endpoint, self.backend.clone()).await?;
        self._accept_close_handle = Some(stop_handle);
        Ok(())
    }

    async fn connect(&mut self, endpoint: &str) -> ZmqResult<()> {
        unimplemented!()
    }
}

#[async_trait]
impl MultiPeer for RepSocketBackend {
    async fn peer_connected(
        &self,
        peer_id: &PeerIdentity,
    ) -> (mpsc::Receiver<Message>, oneshot::Receiver<bool>) {
        let default_queue_size = 100;
        let (out_queue, out_queue_receiver) = mpsc::channel(default_queue_size);
        let (in_queue, in_queue_receiver) = mpsc::channel::<Message>(default_queue_size);
        let (stop_handle, stop_callback) = oneshot::channel::<bool>();

        self.peers.insert(
            peer_id.clone(),
            RepPeer {
                identity: peer_id.clone(),
                send_queue: out_queue,
                recv_queue_in: in_queue,
                _io_close_handle: stop_handle,
            },
        );
        self.peer_queue_in.clone().try_send(
            (peer_id.clone(), in_queue_receiver)
        ).unwrap();

        (out_queue_receiver, stop_callback)
    }

    async fn peer_disconnected(&self, peer_id: &PeerIdentity) {
        self.peers.remove(peer_id);
    }
}

#[async_trait]
impl SocketBackend for RepSocketBackend {
    async fn message_received(&self, peer_id: &PeerIdentity, message: Message) {
        self.peers
            .get_mut(peer_id)
            .expect("Not found peer by id")
            .recv_queue_in
            .send(message)
            .await
            .expect("Failed to send");
    }

    fn socket_type(&self) -> SocketType {
        SocketType::REP
    }

    fn shutdown(&self) {
        self.peers.clear();
    }
}

#[async_trait]
impl BlockingSend for RepSocket {
    async fn send(&mut self, message: ZmqMessage) -> ZmqResult<()> {
        match self.current_request.take() {
            Some(peer_id) => {
                if let Some(mut peer) = self.backend.peers.get_mut(&peer_id) {
                    let frames = vec![
                        "".into(), // delimiter frame
                        message,
                    ];
                    peer.send_queue
                        .send(Message::MultipartMessage(frames))
                        .await?;
                    Ok(())
                } else {
                    Err(ZmqError::Other("Client disconnected"))
                }
            }
            None => Err(ZmqError::Other(
                "Unable to send reply. No request in progress",
            )),
        }
    }
}

#[async_trait]
impl BlockingRecv for RepSocket {
    async fn recv(&mut self) -> ZmqResult<ZmqMessage> {
        loop {
            match self.fair_queue.next().await {
                Some((peer_id, Message::MultipartMessage(mut messages))) => {
                    assert!(messages.len() == 2);
                    assert!(messages[0].data.is_empty()); // Ensure that we have delimeter as first part
                    self.current_request = Some(peer_id);
                    return Ok(messages.pop().unwrap());
                }
                Some((_peer_id, _)) => todo!(),
                None => todo!(),
            };
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "reqwest")]
extern crate reqwest;

use Value;
use error::{RequestError, RequestErrorKind};
use utils::escape_xml;
use transport::Transport;
use parser::parse_response;

use std::io::{self, Write};
use std::collections::BTreeMap;

/// A request to call a procedure.
#[derive(Clone, Debug)]
pub struct Request<'a> {
    name: &'a str,
    args: Vec<Value>,
}

impl<'a> Request<'a> {
    /// Creates a new request to call a function named `name`.
    ///
    /// By default, no arguments are passed. Use the `arg` method to append arguments.
    pub fn new(name: &'a str) -> Self {
        Request {
            name,
            args: Vec::new(),
        }
    }

    /// Appends an argument to be passed to the current list of arguments.
    pub fn arg<T: Into<Value>>(mut self, value: T) -> Self {
        self.args.push(value.into());
        self
    }

    /// Performs the request using a `transport`.
    ///
    /// Returns a `RequestResult` indicating whether the request was sent and processed successfully
    /// (according to the rules of XML-RPC).
    pub fn call<T: Transport>(&self, transport: T) -> RequestResult {
        let mut reader = transport.transmit(self)
            .map_err(RequestErrorKind::TransportError)?;

        let response = parse_response(&mut reader).map_err(RequestErrorKind::ParseError)?;

        let value = response.map_err(RequestErrorKind::Fault)?;
        Ok(value)
    }

    /// Performs the request on a URL.
    ///
    /// This is a convenience method that will internally create a new `reqwest::Client` and send a
    /// POST HTTP request to the given URL. If you only use this method to perform requests, you
    /// don't need to depend on `reqwest` yourself.
    ///
    /// This method is only available when the `reqwest` feature is enabled (this is the default).
    #[cfg(feature = "reqwest")]
    pub fn call_url(&self, url: &str) -> RequestResult {
        self.call(reqwest::Client::new().post(url))
    }

    /// Formats this `Request` as XML.
    pub fn write_as_xml<W: Write>(&self, fmt: &mut W) -> io::Result<()> {
        write!(fmt, r#"<?xml version="1.0" encoding="utf-8"?>"#)?;
        write!(fmt, r#"<methodCall>"#)?;
        write!(fmt, r#"    <methodName>{}</methodName>"#, escape_xml(&self.name))?;
        write!(fmt, r#"    <params>"#)?;
        for value in &self.args {
            write!(fmt, r#"        <param>"#)?;
            value.write_as_xml(fmt)?;
            write!(fmt, r#"        </param>"#)?;
        }
        write!(fmt, r#"    </params>"#)?;
        write!(fmt, r#"</methodCall>"#)?;
        Ok(())
    }

    /// Serialize this `Request` into an XML-RPC struct that can be passed to
    /// the [`system.multicall`](https://mirrors.talideon.com/articles/multicall.html)
    /// XML-RPC method, specifically a struct with two fields:
    ///
    /// * `methodName`: the request name
    /// * `params`: the request arguments
    pub fn into_multicall_struct(self) -> Value {
        let mut multicall_struct: BTreeMap<String, Value> = BTreeMap::new();

        multicall_struct.insert("methodName".into(), self.name.into());
        multicall_struct.insert("params".into(), Value::Array(self.args));

        Value::Struct(multicall_struct)
    }
}

/// The result of executing a request.
pub type RequestResult = Result<Value, RequestError>;

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

    #[test]
    fn escapes_method_names() {
        let mut output: Vec<u8> = Vec::new();
        let req = Request::new("x<&x");

        req.write_as_xml(&mut output).unwrap();
        assert!(
            str::from_utf8(&output)
            .unwrap()
            .contains("<methodName>x<&x</methodName>"));
    }
}
<commit_msg>More doc links<commit_after>#[cfg(feature = "reqwest")]
extern crate reqwest;

use Value;
use error::{RequestError, RequestErrorKind};
use utils::escape_xml;
use transport::Transport;
use parser::parse_response;

use std::io::{self, Write};
use std::collections::BTreeMap;

/// A request to call a procedure.
#[derive(Clone, Debug)]
pub struct Request<'a> {
    name: &'a str,
    args: Vec<Value>,
}

impl<'a> Request<'a> {
    /// Creates a new request to call a function named `name`.
    ///
    /// By default, no arguments are passed. Use the `arg` method to append arguments.
    pub fn new(name: &'a str) -> Self {
        Request {
            name,
            args: Vec::new(),
        }
    }

    /// Appends an argument to be passed to the current list of arguments.
    pub fn arg<T: Into<Value>>(mut self, value: T) -> Self {
        self.args.push(value.into());
        self
    }

    /// Performs the request using a [`Transport`].
    ///
    /// Returns a [`RequestResult`] indicating whether the request was sent and processed
    /// successfully (according to the rules of XML-RPC).
    ///
    /// [`Transport`]: trait.Transport.html
    /// [`RequestResult`]: type.RequestResult.html
    pub fn call<T: Transport>(&self, transport: T) -> RequestResult {
        let mut reader = transport.transmit(self)
            .map_err(RequestErrorKind::TransportError)?;

        let response = parse_response(&mut reader).map_err(RequestErrorKind::ParseError)?;

        let value = response.map_err(RequestErrorKind::Fault)?;
        Ok(value)
    }

    /// Performs the request on a URL.
    ///
    /// This is a convenience method that will internally create a new `reqwest::Client` and send a
    /// POST HTTP request to the given URL. If you only use this method to perform requests, you
    /// don't need to depend on `reqwest` yourself.
    ///
    /// This method is only available when the `reqwest` feature is enabled (this is the default).
    #[cfg(feature = "reqwest")]
    pub fn call_url(&self, url: &str) -> RequestResult {
        self.call(reqwest::Client::new().post(url))
    }

    /// Formats this `Request` as XML.
    pub fn write_as_xml<W: Write>(&self, fmt: &mut W) -> io::Result<()> {
        write!(fmt, r#"<?xml version="1.0" encoding="utf-8"?>"#)?;
        write!(fmt, r#"<methodCall>"#)?;
        write!(fmt, r#"    <methodName>{}</methodName>"#, escape_xml(&self.name))?;
        write!(fmt, r#"    <params>"#)?;
        for value in &self.args {
            write!(fmt, r#"        <param>"#)?;
            value.write_as_xml(fmt)?;
            write!(fmt, r#"        </param>"#)?;
        }
        write!(fmt, r#"    </params>"#)?;
        write!(fmt, r#"</methodCall>"#)?;
        Ok(())
    }

    /// Serialize this `Request` into an XML-RPC struct that can be passed to
    /// the [`system.multicall`](https://mirrors.talideon.com/articles/multicall.html)
    /// XML-RPC method, specifically a struct with two fields:
    ///
    /// * `methodName`: the request name
    /// * `params`: the request arguments
    pub fn into_multicall_struct(self) -> Value {
        let mut multicall_struct: BTreeMap<String, Value> = BTreeMap::new();

        multicall_struct.insert("methodName".into(), self.name.into());
        multicall_struct.insert("params".into(), Value::Array(self.args));

        Value::Struct(multicall_struct)
    }
}

/// The result of executing a request.
pub type RequestResult = Result<Value, RequestError>;

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

    #[test]
    fn escapes_method_names() {
        let mut output: Vec<u8> = Vec::new();
        let req = Request::new("x<&x");

        req.write_as_xml(&mut output).unwrap();
        assert!(
            str::from_utf8(&output)
            .unwrap()
            .contains("<methodName>x<&x</methodName>"));
    }
}
<|endoftext|>


<commit_before>use std::cmp::{Ordering, PartialOrd, Ord};
use std::collections::{BTreeMap, btree_map};
use std::ops::Deref;
use std::str::FromStr;

use rustc_serialize::{Decoder, Decodable};

pub type Path = Option<String>;

#[derive(Debug, PartialEq, Eq)]
pub struct RoutingTable<H>(BTreeMap<Host, BTreeMap<Path, H>>);

#[derive(Debug, PartialEq, Eq)]
pub struct Host(String);

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Match<'a> {
    Word(&'a str),
    Asterisk,
}

impl<T: Decodable> Decodable for RoutingTable<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        d.read_map(|mut d, n| {
            let mut rv = BTreeMap::new();
            for idx in 0..n {
                let (host, path) = d.read_map_elt_key(idx, |mut d| {
                    d.read_str().map(parse_host_path)
                })?;
                let val = d.read_map_elt_val(idx, T::decode)?;
                rv.entry(host)
                .or_insert_with(|| BTreeMap::new())
                .insert(path, val);
            }
            Ok(RoutingTable(rv))
        })
    }
}

impl<T> RoutingTable<T> {
    pub fn hosts(&self) -> btree_map::Iter<Host, BTreeMap<Path, T>> {
        self.0.iter()
    }
    #[allow(dead_code)]
    pub fn num_hosts(&self) -> usize {
        self.0.len()
    }
}

impl<'a> Match<'a> {
    fn new(val: &'a str) -> Match<'a> {
        if val == "*" {
            Match::Asterisk
        } else {
            Match::Word(val)
        }
    }
}

impl Ord for Host {
    fn cmp(&self, other: &Host) -> Ordering {
        let a = self.0.split('.').rev().map(Match::new);
        let b = other.0.split('.').rev().map(Match::new);
        a.cmp(b)
    }
}

impl PartialOrd for Host {
    fn partial_cmp(&self, other: &Host) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Host {
    pub fn matches(&self, host: &str) -> bool {
        let h = self.0.as_str();
        if h.starts_with("*.") {
            host.ends_with(&h[1..])
        } else {
            host == h
        }
    }
}

impl FromStr for Host {
    type Err = ();

    fn from_str(val: &str) -> Result<Host, ()> {
        Ok(Host(val.to_string()))
    }
}

impl Deref for Host {
    type Target = String;

    fn deref(&self) -> &String {
        &self.0
    }
}

fn parse_host_path(val: String) -> (Host, Path) {
    let (host, path) = if let Some(i) = val.find('/') {
        if &val[i..] == "/" {
            (&val[..i], None)
        } else {
            (&val[..i], Some(val[i..].to_string()))
        }
    } else {
        (val.as_str(), None)
    };
    (host.parse().unwrap(), path)
}

/// Map host port to a route of arbitrary type
///
/// Returns destination route and relative path
pub fn route<'x, D>(host: &str, path: &'x str,
    table: &'x RoutingTable<D>)
    -> Option<(&'x D, &'x str, &'x str)>
{
    // TODO(tailhook) transform into range iteration when `btree_range` is
    // stable
    for (route_host, sub_table) in table.hosts() {
        if route_host.matches(host) {
            for (route_path, result) in sub_table.iter().rev() {
                if path_match(&route_path, path) {
                    // Longest match is the last in reversed iteration
                    let prefix = route_path.as_ref().map(|x| &x[..]).unwrap_or("");
                    return Some((result, prefix, &path[prefix.len()..]));
                }
            }
            return None;
        }
    }
    return None;
}

fn path_match<S: AsRef<str>>(pattern: &Option<S>, value: &str) -> bool {
    if let Some(ref prefix) = *pattern {
        let prefix = prefix.as_ref();
        if value.starts_with(prefix) && (
                value.len() == prefix.len() ||
                value[prefix.len()..].starts_with("/") ||
                value[prefix.len()..].starts_with("?"))
        {
            return true;
        }
        return false;
    } else {
        return true;
    }
}

/// Returns host with trimmed whitespace and without port number if exists
pub fn parse_host(host_header: &str) -> &str {
    match host_header.find(':') {
        Some(idx) => &host_header[..idx],
        None => host_header,
    }.trim()
}

#[cfg(test)]
mod route_test {
    use super::{Host, Path};
    use super::route;
    use super::RoutingTable;

    #[test]
    fn route_host() {
        let table = RoutingTable(vec![
            ("example.com".parse().unwrap(), vec![
                (None, 1),
                ].into_iter().collect()),
            ].into_iter().collect());
        assert_eq!(route("example.com", "/hello", &table),
                   Some((&1, "", "/hello")));
        assert_eq!(route("example.com", "/", &table),
                   Some((&1, "", "/")));
        assert_eq!(route("example.org", "/hello", &table), None);
        assert_eq!(route("example.org", "/", &table), None);
    }

    #[test]
    fn route_host_suffix() {
        // Routing table
        //   example.com: 1
        //   *.example.com: 2
        //   *.example.com/static: 3
        //   www.example.com/static/favicon.ico: 4
        //   xxx.example.com: 5
        //   *.aaa.example.com: 6
        let table = RoutingTable(vec![
            ("example.com".parse().unwrap(), vec![
                (None, 1),
                ].into_iter().collect()),
            ("*.example.com".parse().unwrap(), vec![
                (None, 2),
                (Some("/static".into()), 3),
                ].into_iter().collect()),
            ("www.example.com".parse().unwrap(), vec![
                (Some("/static/favicon.ico".into()), 4),
                ].into_iter().collect()),
            ("xxx.example.com".parse().unwrap(), vec![
                (None, 5),
                ].into_iter().collect()),
            ("*.aaa.example.com".parse().unwrap(), vec![
                (None, 6),
                ].into_iter().collect()),
            ].into_iter().collect());

        assert_eq!(route("test.example.com", "/hello", &table),
                   Some((&2, "", "/hello")));
        assert_eq!(route("www.example.com", "/", &table), None);
        assert_eq!(route("www.example.com", "/static/i", &table), None);
        assert_eq!(route("www.example.com", "/static/favicon.ico", &table),
                   Some((&4, "/static/favicon.ico", "")));
        assert_eq!(route("xxx.example.com", "/hello", &table),
                   Some((&5, "", "/hello")));
        assert_eq!(route("example.org", "/", &table), None);
        assert_eq!(route("example.com", "/hello", &table),
                   Some((&1, "", "/hello")));
        assert_eq!(route("xxx.aaa.example.com", "/hello", &table),
                   Some((&6, "", "/hello")));
        assert_eq!(route("city.example.com", "/static", &table),
                   Some((&3, "/static", "")));
    }

    #[test]
    fn route_path() {
        let table = RoutingTable(vec![
            ("ex.com".parse().unwrap(), vec![
                (None , 0),
                (Some("/one".into()), 1),
                (Some("/two".into()) , 2),
                ].into_iter().collect()),
            ].into_iter().collect());
        assert_eq!(route("ex.com", "/one", &table),
                   Some((&1, "/one", "")));
        assert_eq!(route("ex.com", "/one/end", &table),
                   Some((&1, "/one", "/end")));
        assert_eq!(route("ex.com", "/two", &table),
                   Some((&2, "/two", "")));
        assert_eq!(route("ex.com","/two/some", &table),
                   Some((&2, "/two", "/some")));
        assert_eq!(route("ex.com", "/three", &table),
                   Some((&0, "", "/three")));
        assert_eq!(route("ex.com", "/", &table),
                   Some((&0, "", "/")));
        assert_eq!(route("ex.org", "/one", &table), None);
        assert_eq!(route("subdomain.ex.org", "/two", &table), None);
        assert_eq!(route("example.org", "/", &table), None);
        assert_eq!(route("example.org", "/two", &table), None);
    }

}

#[cfg(test)]
mod parse_test {
    use super::{Host, Path};
    use super::parse_host_path;

    #[test]
    fn simple() {
        let s = "example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn base_host() {
        let s = "*.example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn invalid_base_host() {
        let s = "*example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*example.com".into()));
        assert!(path.is_none());

        let s = ".example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host(".example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn invalid_host() {
        // FiXME: only dot is invalid
        let s = "*.".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.".into()));
        assert!(path.is_none());

        let s = "*./".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.".into()));
        assert!(path.is_none());
    }

    #[test]
    fn match_host() {
        let h = Host("example.com".into());
        assert!(h.matches("example.com"));
        assert!(!h.matches(".example.com"));
        assert!(!h.matches("www.example.com"));

        let h = Host("*.example.com".into());
        assert!(!h.matches("example.com"));
        assert!(h.matches("xxx.example.com"));
        assert!(h.matches("www.example.com"));
    }

    #[test]
    fn ordering() {
        let mut ordered: Vec<Host> = vec![
            "aaa".parse().unwrap(),
            "*.bbb".parse().unwrap(),
            "*.aaa.bbb".parse().unwrap(),
            "*.zzz.bbb".parse().unwrap(),
            "aaa.zzz".parse().unwrap(),
        ];
        ordered.sort();
        assert_eq!(ordered, [
            Host("aaa".into()),
            Host("*.aaa.bbb".into()),
            Host("*.zzz.bbb".into()),
            Host("*.bbb".into()),
            Host("aaa.zzz".into()),
        ]);
        ordered.reverse();
        assert_eq!(ordered, [
            Host("aaa.zzz".into()),
            Host("*.bbb".into()),
            Host("*.zzz.bbb".into()),
            Host("*.aaa.bbb".into()),
            Host("aaa".into()),
        ]);
    }

}
<commit_msg>Additional condition on routing test<commit_after>use std::cmp::{Ordering, PartialOrd, Ord};
use std::collections::{BTreeMap, btree_map};
use std::ops::Deref;
use std::str::FromStr;

use rustc_serialize::{Decoder, Decodable};

pub type Path = Option<String>;

#[derive(Debug, PartialEq, Eq)]
pub struct RoutingTable<H>(BTreeMap<Host, BTreeMap<Path, H>>);

#[derive(Debug, PartialEq, Eq)]
pub struct Host(String);

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Match<'a> {
    Word(&'a str),
    Asterisk,
}

impl<T: Decodable> Decodable for RoutingTable<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        d.read_map(|mut d, n| {
            let mut rv = BTreeMap::new();
            for idx in 0..n {
                let (host, path) = d.read_map_elt_key(idx, |mut d| {
                    d.read_str().map(parse_host_path)
                })?;
                let val = d.read_map_elt_val(idx, T::decode)?;
                rv.entry(host)
                .or_insert_with(|| BTreeMap::new())
                .insert(path, val);
            }
            Ok(RoutingTable(rv))
        })
    }
}

impl<T> RoutingTable<T> {
    pub fn hosts(&self) -> btree_map::Iter<Host, BTreeMap<Path, T>> {
        self.0.iter()
    }
    #[allow(dead_code)]
    pub fn num_hosts(&self) -> usize {
        self.0.len()
    }
}

impl<'a> Match<'a> {
    fn new(val: &'a str) -> Match<'a> {
        if val == "*" {
            Match::Asterisk
        } else {
            Match::Word(val)
        }
    }
}

impl Ord for Host {
    fn cmp(&self, other: &Host) -> Ordering {
        let a = self.0.split('.').rev().map(Match::new);
        let b = other.0.split('.').rev().map(Match::new);
        a.cmp(b)
    }
}

impl PartialOrd for Host {
    fn partial_cmp(&self, other: &Host) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Host {
    pub fn matches(&self, host: &str) -> bool {
        let h = self.0.as_str();
        if h.starts_with("*.") {
            host.ends_with(&h[1..])
        } else {
            host == h
        }
    }
}

impl FromStr for Host {
    type Err = ();

    fn from_str(val: &str) -> Result<Host, ()> {
        Ok(Host(val.to_string()))
    }
}

impl Deref for Host {
    type Target = String;

    fn deref(&self) -> &String {
        &self.0
    }
}

fn parse_host_path(val: String) -> (Host, Path) {
    let (host, path) = if let Some(i) = val.find('/') {
        if &val[i..] == "/" {
            (&val[..i], None)
        } else {
            (&val[..i], Some(val[i..].to_string()))
        }
    } else {
        (val.as_str(), None)
    };
    (host.parse().unwrap(), path)
}

/// Map host port to a route of arbitrary type
///
/// Returns destination route and relative path
pub fn route<'x, D>(host: &str, path: &'x str,
    table: &'x RoutingTable<D>)
    -> Option<(&'x D, &'x str, &'x str)>
{
    // TODO(tailhook) transform into range iteration when `btree_range` is
    // stable
    for (route_host, sub_table) in table.hosts() {
        if route_host.matches(host) {
            for (route_path, result) in sub_table.iter().rev() {
                if path_match(&route_path, path) {
                    // Longest match is the last in reversed iteration
                    let prefix = route_path.as_ref().map(|x| &x[..]).unwrap_or("");
                    return Some((result, prefix, &path[prefix.len()..]));
                }
            }
            return None;
        }
    }
    return None;
}

fn path_match<S: AsRef<str>>(pattern: &Option<S>, value: &str) -> bool {
    if let Some(ref prefix) = *pattern {
        let prefix = prefix.as_ref();
        if value.starts_with(prefix) && (
                value.len() == prefix.len() ||
                value[prefix.len()..].starts_with("/") ||
                value[prefix.len()..].starts_with("?"))
        {
            return true;
        }
        return false;
    } else {
        return true;
    }
}

/// Returns host with trimmed whitespace and without port number if exists
pub fn parse_host(host_header: &str) -> &str {
    match host_header.find(':') {
        Some(idx) => &host_header[..idx],
        None => host_header,
    }.trim()
}

#[cfg(test)]
mod route_test {
    use super::{Host, Path};
    use super::route;
    use super::RoutingTable;

    #[test]
    fn route_host() {
        let table = RoutingTable(vec![
            ("example.com".parse().unwrap(), vec![
                (None, 1),
                ].into_iter().collect()),
            ].into_iter().collect());
        assert_eq!(route("example.com", "/hello", &table),
                   Some((&1, "", "/hello")));
        assert_eq!(route("example.com", "/", &table),
                   Some((&1, "", "/")));
        assert_eq!(route("example.org", "/hello", &table), None);
        assert_eq!(route("example.org", "/", &table), None);
    }

    #[test]
    fn route_host_suffix() {
        // Routing table
        //   example.com: 1
        //   *.example.com: 2
        //   *.example.com/static: 3
        //   www.example.com/static/favicon.ico: 4
        //   xxx.example.com: 5
        //   *.aaa.example.com: 6
        let table = RoutingTable(vec![
            ("example.com".parse().unwrap(), vec![
                (None, 1),
                ].into_iter().collect()),
            ("*.example.com".parse().unwrap(), vec![
                (None, 2),
                (Some("/static".into()), 3),
                ].into_iter().collect()),
            ("www.example.com".parse().unwrap(), vec![
                (Some("/static/favicon.ico".into()), 4),
                ].into_iter().collect()),
            ("xxx.example.com".parse().unwrap(), vec![
                (None, 5),
                ].into_iter().collect()),
            ("*.aaa.example.com".parse().unwrap(), vec![
                (None, 6),
                ].into_iter().collect()),
            ].into_iter().collect());

        assert_eq!(route("test.example.com", "/hello", &table),
                   Some((&2, "", "/hello")));
        assert_eq!(route("www.example.com", "/", &table), None);
        assert_eq!(route("www.example.com", "/static/i", &table), None);
        assert_eq!(route("www.example.com", "/static/favicon.ico", &table),
                   Some((&4, "/static/favicon.ico", "")));
        assert_eq!(route("xxx.example.com", "/hello", &table),
                   Some((&5, "", "/hello")));
        assert_eq!(route("example.org", "/", &table), None);
        assert_eq!(route("example.com", "/hello", &table),
                   Some((&1, "", "/hello")));
        assert_eq!(route("xxx.aaa.example.com", "/hello", &table),
                   Some((&6, "", "/hello")));
        assert_eq!(route("aaa.example.com", "/hello", &table),
                   Some((&6, "", "/hello")));
        assert_eq!(route("city.example.com", "/static", &table),
                   Some((&3, "/static", "")));
    }

    #[test]
    fn route_path() {
        let table = RoutingTable(vec![
            ("ex.com".parse().unwrap(), vec![
                (None , 0),
                (Some("/one".into()), 1),
                (Some("/two".into()) , 2),
                ].into_iter().collect()),
            ].into_iter().collect());
        assert_eq!(route("ex.com", "/one", &table),
                   Some((&1, "/one", "")));
        assert_eq!(route("ex.com", "/one/end", &table),
                   Some((&1, "/one", "/end")));
        assert_eq!(route("ex.com", "/two", &table),
                   Some((&2, "/two", "")));
        assert_eq!(route("ex.com","/two/some", &table),
                   Some((&2, "/two", "/some")));
        assert_eq!(route("ex.com", "/three", &table),
                   Some((&0, "", "/three")));
        assert_eq!(route("ex.com", "/", &table),
                   Some((&0, "", "/")));
        assert_eq!(route("ex.org", "/one", &table), None);
        assert_eq!(route("subdomain.ex.org", "/two", &table), None);
        assert_eq!(route("example.org", "/", &table), None);
        assert_eq!(route("example.org", "/two", &table), None);
    }

}

#[cfg(test)]
mod parse_test {
    use super::{Host, Path};
    use super::parse_host_path;

    #[test]
    fn simple() {
        let s = "example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn base_host() {
        let s = "*.example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn invalid_base_host() {
        let s = "*example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*example.com".into()));
        assert!(path.is_none());

        let s = ".example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host(".example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn invalid_host() {
        // FiXME: only dot is invalid
        let s = "*.".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.".into()));
        assert!(path.is_none());

        let s = "*./".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.".into()));
        assert!(path.is_none());
    }

    #[test]
    fn match_host() {
        let h = Host("example.com".into());
        assert!(h.matches("example.com"));
        assert!(!h.matches(".example.com"));
        assert!(!h.matches("www.example.com"));

        let h = Host("*.example.com".into());
        assert!(!h.matches("example.com"));
        assert!(h.matches("xxx.example.com"));
        assert!(h.matches("www.example.com"));
    }

    #[test]
    fn ordering() {
        let mut ordered: Vec<Host> = vec![
            "aaa".parse().unwrap(),
            "*.bbb".parse().unwrap(),
            "*.aaa.bbb".parse().unwrap(),
            "*.zzz.bbb".parse().unwrap(),
            "aaa.zzz".parse().unwrap(),
        ];
        ordered.sort();
        assert_eq!(ordered, [
            Host("aaa".into()),
            Host("*.aaa.bbb".into()),
            Host("*.zzz.bbb".into()),
            Host("*.bbb".into()),
            Host("aaa.zzz".into()),
        ]);
        ordered.reverse();
        assert_eq!(ordered, [
            Host("aaa.zzz".into()),
            Host("*.bbb".into()),
            Host("*.zzz.bbb".into()),
            Host("*.aaa.bbb".into()),
            Host("aaa".into()),
        ]);
    }

}
<|endoftext|>


<commit_before>use std::fmt::Display;
use thiserror::Error;

// Some of the elaborate cases from the rcc codebase, which is a C compiler in
// Rust. https://github.com/jyn514/rcc/blob/0.8.0/src/data/error.rs
#[derive(Error, Debug)]
pub enum Error {
    #[error("cannot shift {} by {maximum} or more bits (got {current})", if *.is_left { "left" } else { "right" })]
    TooManyShiftBits {
        is_left: bool,
        maximum: u64,
        current: u64,
    },

    #[error("#error {}", (.0).iter().copied().collect::<Vec<_>>().join(" "))]
    User(Vec<&'static str>),

    #[error("overflow while parsing {}integer literal",
        if let Some(signed) = .is_signed {
            if *signed { "signed "} else { "unsigned "}
        } else {
            ""
        }
    )]
    IntegerOverflow { is_signed: Option<bool> },

    #[error("overflow while parsing {}integer literal", match .is_signed {
        Some(true) => "signed ",
        Some(false) => "unsigned ",
        None => "",
    })]
    IntegerOverflow2 { is_signed: Option<bool> },
}

fn assert<T: Display>(expected: &str, value: T) {
    assert_eq!(expected, value.to_string());
}

#[test]
fn test_rcc() {
    assert(
        "cannot shift left by 32 or more bits (got 50)",
        Error::TooManyShiftBits {
            is_left: true,
            maximum: 32,
            current: 50,
        },
    );

    assert("#error A B C", Error::User(vec!["A", "B", "C"]));

    assert(
        "overflow while parsing signed integer literal",
        Error::IntegerOverflow {
            is_signed: Some(true),
        },
    );
}
<commit_msg>Add expr test cases from rustup<commit_after>use std::fmt::Display;
use thiserror::Error;

// Some of the elaborate cases from the rcc codebase, which is a C compiler in
// Rust. https://github.com/jyn514/rcc/blob/0.8.0/src/data/error.rs
#[derive(Error, Debug)]
pub enum CompilerError {
    #[error("cannot shift {} by {maximum} or more bits (got {current})", if *.is_left { "left" } else { "right" })]
    TooManyShiftBits {
        is_left: bool,
        maximum: u64,
        current: u64,
    },

    #[error("#error {}", (.0).iter().copied().collect::<Vec<_>>().join(" "))]
    User(Vec<&'static str>),

    #[error("overflow while parsing {}integer literal",
        if let Some(signed) = .is_signed {
            if *signed { "signed "} else { "unsigned "}
        } else {
            ""
        }
    )]
    IntegerOverflow { is_signed: Option<bool> },

    #[error("overflow while parsing {}integer literal", match .is_signed {
        Some(true) => "signed ",
        Some(false) => "unsigned ",
        None => "",
    })]
    IntegerOverflow2 { is_signed: Option<bool> },
}

// Examples drawn from Rustup.
#[derive(Error, Debug)]
pub enum RustupError {
    #[error(
        "toolchain '{name}' does not contain component {component}{}",
        .suggestion
            .as_ref()
            .map(|s| format!("; did you mean '{}'?", s))
            .unwrap_or_else(String::new),
    )]
    UnknownComponent {
        name: String,
        component: String,
        suggestion: Option<String>,
    },
}

fn assert<T: Display>(expected: &str, value: T) {
    assert_eq!(expected, value.to_string());
}

#[test]
fn test_rcc() {
    assert(
        "cannot shift left by 32 or more bits (got 50)",
        CompilerError::TooManyShiftBits {
            is_left: true,
            maximum: 32,
            current: 50,
        },
    );

    assert("#error A B C", CompilerError::User(vec!["A", "B", "C"]));

    assert(
        "overflow while parsing signed integer literal",
        CompilerError::IntegerOverflow {
            is_signed: Some(true),
        },
    );
}

#[test]
fn test_rustup() {
    assert(
        "toolchain 'nightly' does not contain component clipy; did you mean 'clippy'?",
        RustupError::UnknownComponent {
            name: "nightly".to_owned(),
            component: "clipy".to_owned(),
            suggestion: Some("clippy".to_owned()),
        },
    );
}
<|endoftext|>


<commit_before>//! Types in this module are mostly internal and automatically generated. You
//! shouldn't need to interact with these types during normal usage, other than
//! the methods on [`Table`](/diesel/query_source/trait.Table.html)
#[doc(hidden)]
pub mod joins;
mod peano_numbers;

use std::error::Error;

use backend::Backend;
use expression::{Expression, NonAggregate, SelectableExpression};
use query_builder::*;
use row::NamedRow;
use types::{FromSqlRow, HasSqlType};

pub use self::joins::JoinTo;
pub use self::peano_numbers::*;

/// Trait indicating that a record can be queried from the database. This trait
/// can be derived automatically using `diesel_codegen`. This trait can only be derived for
/// structs, not enums.
pub trait Queryable<ST, DB>
where
    DB: Backend + HasSqlType<ST>,
{
    type Row: FromSqlRow<ST, DB>;

    fn build(row: Self::Row) -> Self;
}

/// Deserializes the result of a query constructed with [`sql_query`].
///
/// # Deriving
///
/// This trait can be automatically derived by `diesel_codegen`. To derive this
/// trait, the struct must be associated with a single table. If the table name
/// is different than `"struct_name" + "s"`, you can annotate your struct with
/// `#[table_name = "some_table"]`.
///
/// The module for that table must be in scope. For example, to derive this for
/// a struct called `User`, you will likely need a line such as `use
/// schema::users;`
///
/// If the name of a field on your struct is different than the column in your
/// `table!` declaration, or if you are deriving this trait on a tuple struct,
/// you can annotate the field with `#[column_name = "some_column"]`. For tuple
/// structs, all fields must have this annotation.
///
/// [`sql_query`]: ../fn.sql_query.html
pub trait QueryableByName<DB>
where
    Self: Sized,
    DB: Backend,
{
    fn build<R: NamedRow<DB>>(row: &R) -> Result<Self, Box<Error + Send + Sync>>;
}

#[doc(hidden)]
pub trait QuerySource {
    type FromClause;
    type DefaultSelection: SelectableExpression<Self>;

    fn from_clause(&self) -> Self::FromClause;
    fn default_selection(&self) -> Self::DefaultSelection;
}

/// A column on a database table. Types which implement this trait should have
/// been generated by the [`table!` macro](../macro.table.html).
pub trait Column: Expression {
    type Table: Table;

    const NAME: &'static str;
}

/// A SQL database table. Types which implement this trait should have been
/// generated by the [`table!` macro](../macro.table.html).
pub trait Table: QuerySource + AsQuery + Sized {
    type PrimaryKey: SelectableExpression<Self> + NonAggregate;
    type AllColumns: SelectableExpression<Self> + NonAggregate;

    fn primary_key(&self) -> Self::PrimaryKey;
    fn all_columns() -> Self::AllColumns;
}

pub trait AppearsInFromClause<QS> {
    type Count;
}
<commit_msg>Document `AppearsInFromClause`<commit_after>//! Types in this module are mostly internal and automatically generated. You
//! shouldn't need to interact with these types during normal usage, other than
//! the methods on [`Table`](/diesel/query_source/trait.Table.html)
#[doc(hidden)]
pub mod joins;
mod peano_numbers;

use std::error::Error;

use backend::Backend;
use expression::{Expression, NonAggregate, SelectableExpression};
use query_builder::*;
use row::NamedRow;
use types::{FromSqlRow, HasSqlType};

pub use self::joins::JoinTo;
pub use self::peano_numbers::*;

/// Trait indicating that a record can be queried from the database. This trait
/// can be derived automatically using `diesel_codegen`. This trait can only be derived for
/// structs, not enums.
pub trait Queryable<ST, DB>
where
    DB: Backend + HasSqlType<ST>,
{
    type Row: FromSqlRow<ST, DB>;

    fn build(row: Self::Row) -> Self;
}

/// Deserializes the result of a query constructed with [`sql_query`].
///
/// # Deriving
///
/// This trait can be automatically derived by `diesel_codegen`. To derive this
/// trait, the struct must be associated with a single table. If the table name
/// is different than `"struct_name" + "s"`, you can annotate your struct with
/// `#[table_name = "some_table"]`.
///
/// The module for that table must be in scope. For example, to derive this for
/// a struct called `User`, you will likely need a line such as `use
/// schema::users;`
///
/// If the name of a field on your struct is different than the column in your
/// `table!` declaration, or if you are deriving this trait on a tuple struct,
/// you can annotate the field with `#[column_name = "some_column"]`. For tuple
/// structs, all fields must have this annotation.
///
/// [`sql_query`]: ../fn.sql_query.html
pub trait QueryableByName<DB>
where
    Self: Sized,
    DB: Backend,
{
    fn build<R: NamedRow<DB>>(row: &R) -> Result<Self, Box<Error + Send + Sync>>;
}

#[doc(hidden)]
pub trait QuerySource {
    type FromClause;
    type DefaultSelection: SelectableExpression<Self>;

    fn from_clause(&self) -> Self::FromClause;
    fn default_selection(&self) -> Self::DefaultSelection;
}

/// A column on a database table. Types which implement this trait should have
/// been generated by the [`table!` macro](../macro.table.html).
pub trait Column: Expression {
    type Table: Table;

    const NAME: &'static str;
}

/// A SQL database table. Types which implement this trait should have been
/// generated by the [`table!` macro](../macro.table.html).
pub trait Table: QuerySource + AsQuery + Sized {
    type PrimaryKey: SelectableExpression<Self> + NonAggregate;
    type AllColumns: SelectableExpression<Self> + NonAggregate;

    fn primary_key(&self) -> Self::PrimaryKey;
    fn all_columns() -> Self::AllColumns;
}

/// Determines how many times `Self` appears in `QS`
///
/// This trait is primarily used to determine whether or not a column is
/// selectable from a given from clause. A column can be selected if its table
/// appears in the from clause *exactly once*.
///
/// We do not allow the same table to appear in a query multiple times in any
/// context where referencing that table would be ambiguous (depending on the
/// context and backend being used, this may or may not be something that would
/// otherwise result in a runtime error).
pub trait AppearsInFromClause<QS> {
    /// How many times does `Self` appear in `QS`?
    type Count;
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]

#[deriving(Decodable,Encodable,Show)]
pub struct Node {
    Node: String,
    Address: String,
}

#[deriving(Decodable,Encodable,Show)]
pub struct Service {
    ID: String,
    pub Service: String,
    pub Tags: Vec<String>,
    pub Port: int,
}
<commit_msg>change node field permission<commit_after>#![allow(non_snake_case)]

#[deriving(Decodable,Encodable,Show)]
pub struct Node {
    pub Node: String,
    pub Address: String,
}

#[deriving(Decodable,Encodable,Show)]
pub struct Service {
    ID: String,
    pub Service: String,
    pub Tags: Vec<String>,
    pub Port: int,
}
<|endoftext|>


<commit_before>use ::*;
use errors::*;
use pretty_bytes::converter::convert;
use separator::Separatable;
use std::path::Path;

pub struct Parameters {
    pub compressor: CompressionAlgorithm,
    pub extension: String,
    pub threads: usize,
}

pub enum CompressionAlgorithm {
    Brotli,
    GZip,
    Zopfli,
}

impl std::str::FromStr for CompressionAlgorithm {
    type Err = errors::Error;
    fn from_str(s: &str) -> Result<Self> {
        let r = match s {
            "gzip" => CompressionAlgorithm::GZip,
            "brotli" => CompressionAlgorithm::Brotli,
            "zopfli" => CompressionAlgorithm::Zopfli,
            _ => bail!("Unsupported compression algorithm option set!"),
        };

        return Ok(r);
    }
}

pub trait DefaultFileCompressor {
    fn compress(&self, source: &Path, destination: &Path) -> Result<()>;
}

pub trait FileCompressor {
    fn compress(&self, source: &Path, destination: &Path, level: u8);
}

pub trait CompressionFormat {
    fn extension(&self) -> &'static str;
}

pub struct Statistics {
    total_compressed: u64,
    total_compressed_now: u64,
    total_file_count: u32,
    total_file_count_now: u32,
    total_uncompressed: u64,
    total_uncompressed_now: u64,
}

impl Statistics {
    pub fn new() -> Statistics {
        Statistics {
            total_compressed: 0,
            total_compressed_now: 0,
            total_file_count: 0,
            total_file_count_now: 0,
            total_uncompressed: 0,
            total_uncompressed_now: 0,
        }
    }

    pub fn update(&mut self, uncompressed_size: u64, compressed_size: u64, newly_compressed: bool) {
        if newly_compressed {
            self.total_compressed_now += compressed_size;
            self.total_file_count_now += 1;
            self.total_uncompressed_now += uncompressed_size;
        }

        self.total_compressed += compressed_size;
        self.total_file_count += 1;
        self.total_uncompressed += uncompressed_size;
    }

    pub fn merge(&mut self, other: &Statistics) {
        self.total_compressed += other.total_compressed;
        self.total_compressed_now += other.total_compressed_now;
        self.total_file_count += other.total_file_count;
        self.total_file_count_now += other.total_file_count_now;
        self.total_uncompressed += other.total_uncompressed;
        self.total_uncompressed_now += other.total_uncompressed_now;
    }

    pub fn savings_ratio(&self) -> f32 {
        return self.total_compressed as f32 / self.total_uncompressed as f32;
    }

    pub fn savings_ratio_now(&self) -> f32 {
        return self.total_compressed_now as f32 / self.total_uncompressed_now as f32;
    }
}

impl std::fmt::Display for Statistics {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        writeln!(f, "")?;
        let table = table!(["", "This Run", "Total"],
                           ["Count", self.total_file_count_now.separated_string(), self.total_file_count.separated_string()],
                           ["Compressed Size", convert(self.total_compressed_now as f64), convert(self.total_compressed as f64)],
                           ["Uncompressed Size", convert(self.total_uncompressed_now as f64), convert(self.total_uncompressed as f64)],
                           ["Total Savings", format!("{:.2}%", 100f32 - 100f32 * self.savings_ratio_now()), format!("{:.2}%", 100f32 - 100f32 * self.savings_ratio())]);

        writeln!(f, "{}", table)?;
        Ok(())
    }
}
<commit_msg>Fixed line endings<commit_after>use ::*;
use errors::*;
use pretty_bytes::converter::convert;
use separator::Separatable;
use std::path::Path;

pub struct Parameters {
    pub compressor: CompressionAlgorithm,
    pub extension: String,
    pub threads: usize,
}

pub enum CompressionAlgorithm {
    Brotli,
    GZip,
    Zopfli,
}

impl std::str::FromStr for CompressionAlgorithm {
    type Err = errors::Error;
    fn from_str(s: &str) -> Result<Self> {
        let r = match s {
            "gzip" => CompressionAlgorithm::GZip,
            "brotli" => CompressionAlgorithm::Brotli,
            "zopfli" => CompressionAlgorithm::Zopfli,
            _ => bail!("Unsupported compression algorithm option set!"),
        };

        return Ok(r);
    }
}

pub trait DefaultFileCompressor {
    fn compress(&self, source: &Path, destination: &Path) -> Result<()>;
}

pub trait FileCompressor {
    fn compress(&self, source: &Path, destination: &Path, level: u8);
}

pub trait CompressionFormat {
    fn extension(&self) -> &'static str;
}

pub struct Statistics {
    total_compressed: u64,
    total_compressed_now: u64,
    total_file_count: u32,
    total_file_count_now: u32,
    total_uncompressed: u64,
    total_uncompressed_now: u64,
}

impl Statistics {
    pub fn new() -> Statistics {
        Statistics {
            total_compressed: 0,
            total_compressed_now: 0,
            total_file_count: 0,
            total_file_count_now: 0,
            total_uncompressed: 0,
            total_uncompressed_now: 0,
        }
    }

    pub fn update(&mut self, uncompressed_size: u64, compressed_size: u64, newly_compressed: bool) {
        if newly_compressed {
            self.total_compressed_now += compressed_size;
            self.total_file_count_now += 1;
            self.total_uncompressed_now += uncompressed_size;
        }

        self.total_compressed += compressed_size;
        self.total_file_count += 1;
        self.total_uncompressed += uncompressed_size;
    }

    pub fn merge(&mut self, other: &Statistics) {
        self.total_compressed += other.total_compressed;
        self.total_compressed_now += other.total_compressed_now;
        self.total_file_count += other.total_file_count;
        self.total_file_count_now += other.total_file_count_now;
        self.total_uncompressed += other.total_uncompressed;
        self.total_uncompressed_now += other.total_uncompressed_now;
    }

    pub fn savings_ratio(&self) -> f32 {
        return self.total_compressed as f32 / self.total_uncompressed as f32;
    }

    pub fn savings_ratio_now(&self) -> f32 {
        return self.total_compressed_now as f32 / self.total_uncompressed_now as f32;
    }
}

impl std::fmt::Display for Statistics {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        writeln!(f, "")?;
        let table = table!(["", "This Run", "Total"],
                           ["Count", self.total_file_count_now.separated_string(), self.total_file_count.separated_string()],
                           ["Compressed Size", convert(self.total_compressed_now as f64), convert(self.total_compressed as f64)],
                           ["Uncompressed Size", convert(self.total_uncompressed_now as f64), convert(self.total_uncompressed as f64)],
                           ["Total Savings", format!("{:.2}%", 100f32 - 100f32 * self.savings_ratio_now()), format!("{:.2}%", 100f32 - 100f32 * self.savings_ratio())]);

        writeln!(f, "{}", table)?;
        Ok(())
    }
}
<|endoftext|>