<commit_before>#![cfg(feature = "unstable-grouped")]

use clap::{Arg, Command};

#[test]
fn grouped_value_works() {
    let m = Command::new("cli")
        .arg(
            Arg::new("option")
                .long("option")
                .takes_value(true)
                .multiple_values(true)
                .multiple_occurrences(true),
        )
        .try_get_matches_from(&[
            "cli",
            "--option",
            "fr_FR:mon option 1",
            "en_US:my option 1",
            "--option",
            "fr_FR:mon option 2",
            "en_US:my option 2",
        ])
        .unwrap();
    let grouped_vals: Vec<_> = m.grouped_values_of("option").unwrap().collect();
    assert_eq!(
        grouped_vals,
        vec![
            vec!["fr_FR:mon option 1", "en_US:my option 1",],
            vec!["fr_FR:mon option 2", "en_US:my option 2",],
        ]
    );
}

#[test]
fn issue_1026() {
    let m = Command::new("cli")
        .arg(Arg::new("server").short('s').takes_value(true))
        .arg(Arg::new("user").short('u').takes_value(true))
        .arg(
            Arg::new("target")
                .long("target")
                .takes_value(true)
                .multiple_values(true)
                .multiple_occurrences(true),
        )
        .try_get_matches_from(&[
            "backup", "-s", "server", "-u", "user", "--target", "target1", "file1", "file2",
            "file3", "--target", "target2", "file4", "file5", "file6", "file7", "--target",
            "target3", "file8",
        ])
        .unwrap();
    let grouped_vals: Vec<_> = m.grouped_values_of("target").unwrap().collect();
    assert_eq!(
        grouped_vals,
        vec![
            vec!["target1", "file1", "file2", "file3"],
            vec!["target2", "file4", "file5", "file6", "file7",],
            vec!["target3", "file8"]
        ]
    );
}

#[test]
fn grouped_value_long_flag_delimiter() {
    let m = Command::new("myapp")
        .arg(
            Arg::new("option")
                .long("option")
                .takes_value(true)
                .use_value_delimiter(true)
                .multiple_values(true)
                .multiple_occurrences(true),
        )
        .try_get_matches_from(vec![
            "myapp",
            "--option=hmm",
            "--option=val1,val2,val3",
            "--option",
            "alice,bob",
        ])
        .unwrap();
    let grouped_vals: Vec<_> = m.grouped_values_of("option").unwrap().collect();
    assert_eq!(
        grouped_vals,
        vec![
            vec!["hmm"],
            vec!["val1", "val2", "val3"],
            vec!["alice", "bob"]
        ]
    );
}

#[test]
fn grouped_value_short_flag_delimiter() {
    let m = Command::new("myapp")
        .arg(
            Arg::new("option")
                .short('o')
                .takes_value(true)
                .use_value_delimiter(true)
                .multiple_values(true)
                .multiple_occurrences(true),
        )
        .try_get_matches_from(vec!["myapp", "-o=foo", "-o=val1,val2,val3", "-o=bar"])
        .unwrap();
    let grouped_vals: Vec<_> = m.grouped_values_of("option").unwrap().collect();
    assert_eq!(
        grouped_vals,
        vec![vec!["foo"], vec!["val1", "val2", "val3"], vec!["bar"]]
    );
}

#[test]
fn grouped_value_positional_arg() {
    let m = Command::new("multiple_values")
        .arg(
            Arg::new("pos")
                .help("multiple positionals")
                .takes_value(true)
                .multiple_values(true),
        )
        .try_get_matches_from(vec![
            "myprog", "val1", "val2", "val3", "val4", "val5", "val6",
        ])
        .unwrap();
    let grouped_vals: Vec<_> = m.grouped_values_of("pos").unwrap().collect();
    assert_eq!(
        grouped_vals,
        vec![vec!["val1", "val2", "val3", "val4", "val5", "val6"]]
    );
}

#[test]
fn grouped_value_multiple_positional_arg() {
    let m = Command::new("multiple_values")
        .arg(Arg::new("pos1").help("multiple positionals"))
        .arg(
            Arg::new("pos2")
                .help("multiple positionals")
                .takes_value(true)
                .multiple_values(true),
        )
        .try_get_matches_from(vec![
            "myprog", "val1", "val2", "val3", "val4", "val5", "val6",
        ])
        .unwrap();
    let grouped_vals: Vec<_> = m.grouped_values_of("pos2").unwrap().collect();
    assert_eq!(
        grouped_vals,
        vec![vec!["val2", "val3", "val4", "val5", "val6"]]
    );
}

#[test]
fn grouped_value_multiple_positional_arg_last_multiple() {
    let m = Command::new("multiple_values")
        .arg(Arg::new("pos1").help("multiple positionals"))
        .arg(
            Arg::new("pos2")
                .help("multiple positionals")
                .takes_value(true)
                .multiple_values(true)
                .last(true),
        )
        .try_get_matches_from(vec![
            "myprog", "val1", "--", "val2", "val3", "val4", "val5", "val6",
        ])
        .unwrap();
    let grouped_vals: Vec<_> = m.grouped_values_of("pos2").unwrap().collect();
    assert_eq!(
        grouped_vals,
        vec![vec!["val2", "val3", "val4", "val5", "val6"]]
    );
}

#[test]
fn issue_1374() {
    let cmd = Command::new("MyApp").arg(
        Arg::new("input")
            .takes_value(true)
            .long("input")
            .overrides_with("input")
            .min_values(0)
            .multiple_occurrences(true),
    );
    let matches = cmd
        .clone()
        .try_get_matches_from(&["MyApp", "--input", "a", "b", "c", "--input", "d"])
        .unwrap();
    let vs = matches
        .get_many::<String>("input")
        .unwrap()
        .map(|v| v.as_str());
    assert_eq!(vs.collect::<Vec<_>>(), vec!["a", "b", "c", "d"]);
    let matches = cmd
        .clone()
        .try_get_matches_from(&["MyApp", "--input", "a", "b", "--input", "c", "d"])
        .unwrap();
    let vs = matches
        .get_many::<String>("input")
        .unwrap()
        .map(|v| v.as_str());
    assert_eq!(vs.collect::<Vec<_>>(), vec!["a", "b", "c", "d"]);
}

#[test]
fn issue_2171() {
    let schema = Command::new("ripgrep#1701 reproducer")
        .args_override_self(true)
        .arg(Arg::new("pretty").short('p').long("pretty"))
        .arg(Arg::new("search_zip").short('z').long("search-zip"));

    let test_args = &[
        vec!["reproducer", "-pz", "-p"],
        vec!["reproducer", "-pzp"],
        vec!["reproducer", "-zpp"],
        vec!["reproducer", "-pp", "-z"],
        vec!["reproducer", "-p", "-p", "-z"],
        vec!["reproducer", "-p", "-pz"],
        vec!["reproducer", "-ppz"],
    ];

    for argv in test_args {
        let _ = schema.clone().try_get_matches_from(argv).unwrap();
    }
}
<commit_msg>test(parser): Verify interleaved group behavior<commit_after>#![cfg(feature = "unstable-grouped")]

use clap::{Arg, Command};

#[test]
fn grouped_value_works() {
    let m = Command::new("cli")
        .arg(
            Arg::new("option")
                .long("option")
                .takes_value(true)
                .multiple_values(true)
                .multiple_occurrences(true),
        )
        .try_get_matches_from(&[
            "cli",
            "--option",
            "fr_FR:mon option 1",
            "en_US:my option 1",
            "--option",
            "fr_FR:mon option 2",
            "en_US:my option 2",
        ])
        .unwrap();
    let grouped_vals: Vec<_> = m.grouped_values_of("option").unwrap().collect();
    assert_eq!(
        grouped_vals,
        vec![
            vec!["fr_FR:mon option 1", "en_US:my option 1",],
            vec!["fr_FR:mon option 2", "en_US:my option 2",],
        ]
    );
}

#[test]
fn issue_1026() {
    let m = Command::new("cli")
        .arg(Arg::new("server").short('s').takes_value(true))
        .arg(Arg::new("user").short('u').takes_value(true))
        .arg(
            Arg::new("target")
                .long("target")
                .takes_value(true)
                .multiple_values(true)
                .multiple_occurrences(true),
        )
        .try_get_matches_from(&[
            "backup", "-s", "server", "-u", "user", "--target", "target1", "file1", "file2",
            "file3", "--target", "target2", "file4", "file5", "file6", "file7", "--target",
            "target3", "file8",
        ])
        .unwrap();
    let grouped_vals: Vec<_> = m.grouped_values_of("target").unwrap().collect();
    assert_eq!(
        grouped_vals,
        vec![
            vec!["target1", "file1", "file2", "file3"],
            vec!["target2", "file4", "file5", "file6", "file7",],
            vec!["target3", "file8"]
        ]
    );
}

#[test]
fn grouped_value_long_flag_delimiter() {
    let m = Command::new("myapp")
        .arg(
            Arg::new("option")
                .long("option")
                .takes_value(true)
                .use_value_delimiter(true)
                .multiple_values(true)
                .multiple_occurrences(true),
        )
        .try_get_matches_from(vec![
            "myapp",
            "--option=hmm",
            "--option=val1,val2,val3",
            "--option",
            "alice,bob",
        ])
        .unwrap();
    let grouped_vals: Vec<_> = m.grouped_values_of("option").unwrap().collect();
    assert_eq!(
        grouped_vals,
        vec![
            vec!["hmm"],
            vec!["val1", "val2", "val3"],
            vec!["alice", "bob"]
        ]
    );
}

#[test]
fn grouped_value_short_flag_delimiter() {
    let m = Command::new("myapp")
        .arg(
            Arg::new("option")
                .short('o')
                .takes_value(true)
                .use_value_delimiter(true)
                .multiple_values(true)
                .multiple_occurrences(true),
        )
        .try_get_matches_from(vec!["myapp", "-o=foo", "-o=val1,val2,val3", "-o=bar"])
        .unwrap();
    let grouped_vals: Vec<_> = m.grouped_values_of("option").unwrap().collect();
    assert_eq!(
        grouped_vals,
        vec![vec!["foo"], vec!["val1", "val2", "val3"], vec!["bar"]]
    );
}

#[test]
fn grouped_value_positional_arg() {
    let m = Command::new("multiple_values")
        .arg(
            Arg::new("pos")
                .help("multiple positionals")
                .takes_value(true)
                .multiple_values(true),
        )
        .try_get_matches_from(vec![
            "myprog", "val1", "val2", "val3", "val4", "val5", "val6",
        ])
        .unwrap();
    let grouped_vals: Vec<_> = m.grouped_values_of("pos").unwrap().collect();
    assert_eq!(
        grouped_vals,
        vec![vec!["val1", "val2", "val3", "val4", "val5", "val6"]]
    );
}

#[test]
fn grouped_value_multiple_positional_arg() {
    let m = Command::new("multiple_values")
        .arg(Arg::new("pos1").help("multiple positionals"))
        .arg(
            Arg::new("pos2")
                .help("multiple positionals")
                .takes_value(true)
                .multiple_values(true),
        )
        .try_get_matches_from(vec![
            "myprog", "val1", "val2", "val3", "val4", "val5", "val6",
        ])
        .unwrap();
    let grouped_vals: Vec<_> = m.grouped_values_of("pos2").unwrap().collect();
    assert_eq!(
        grouped_vals,
        vec![vec!["val2", "val3", "val4", "val5", "val6"]]
    );
}

#[test]
fn grouped_value_multiple_positional_arg_last_multiple() {
    let m = Command::new("multiple_values")
        .arg(Arg::new("pos1").help("multiple positionals"))
        .arg(
            Arg::new("pos2")
                .help("multiple positionals")
                .takes_value(true)
                .multiple_values(true)
                .last(true),
        )
        .try_get_matches_from(vec![
            "myprog", "val1", "--", "val2", "val3", "val4", "val5", "val6",
        ])
        .unwrap();
    let grouped_vals: Vec<_> = m.grouped_values_of("pos2").unwrap().collect();
    assert_eq!(
        grouped_vals,
        vec![vec!["val2", "val3", "val4", "val5", "val6"]]
    );
}

#[test]
fn grouped_interleaved_positional_values() {
    let cmd = clap::Command::new("foo")
        .arg(clap::Arg::new("pos").multiple_values(true))
        .arg(
            clap::Arg::new("flag")
                .short('f')
                .long("flag")
                .takes_value(true)
                .multiple_occurrences(true),
        );

    let m = cmd
        .try_get_matches_from(["foo", "1", "2", "-f", "a", "3", "-f", "b", "4"])
        .unwrap();
    let pos: Vec<_> = m.grouped_values_of("pos").unwrap().collect();
    assert_eq!(pos, vec![vec!["1", "2", "3", "4"]]);
    assert_eq!(m.occurrences_of("pos"), 1);
    let flag: Vec<_> = m.grouped_values_of("flag").unwrap().collect();
    assert_eq!(flag, vec![vec!["a"], vec!["b"]]);
    assert_eq!(m.occurrences_of("flag"), 2);
}

#[test]
fn grouped_interleaved_positional_occurrences() {
    let cmd = clap::Command::new("foo")
        .arg(clap::Arg::new("pos").multiple_occurrences(true))
        .arg(
            clap::Arg::new("flag")
                .short('f')
                .long("flag")
                .takes_value(true)
                .multiple_occurrences(true),
        );

    let m = cmd
        .try_get_matches_from(["foo", "1", "2", "-f", "a", "3", "-f", "b", "4"])
        .unwrap();
    let pos: Vec<_> = m.grouped_values_of("pos").unwrap().collect();
    assert_eq!(pos, vec![vec!["1"], vec!["2"], vec!["3"], vec!["4"]]);
    assert_eq!(m.occurrences_of("pos"), 4);
    let flag: Vec<_> = m.grouped_values_of("flag").unwrap().collect();
    assert_eq!(flag, vec![vec!["a"], vec!["b"]]);
    assert_eq!(m.occurrences_of("flag"), 2);
}

#[test]
fn issue_1374() {
    let cmd = Command::new("MyApp").arg(
        Arg::new("input")
            .takes_value(true)
            .long("input")
            .overrides_with("input")
            .min_values(0)
            .multiple_occurrences(true),
    );
    let matches = cmd
        .clone()
        .try_get_matches_from(&["MyApp", "--input", "a", "b", "c", "--input", "d"])
        .unwrap();
    let vs = matches
        .get_many::<String>("input")
        .unwrap()
        .map(|v| v.as_str());
    assert_eq!(vs.collect::<Vec<_>>(), vec!["a", "b", "c", "d"]);
    let matches = cmd
        .clone()
        .try_get_matches_from(&["MyApp", "--input", "a", "b", "--input", "c", "d"])
        .unwrap();
    let vs = matches
        .get_many::<String>("input")
        .unwrap()
        .map(|v| v.as_str());
    assert_eq!(vs.collect::<Vec<_>>(), vec!["a", "b", "c", "d"]);
}

#[test]
fn issue_2171() {
    let schema = Command::new("ripgrep#1701 reproducer")
        .args_override_self(true)
        .arg(Arg::new("pretty").short('p').long("pretty"))
        .arg(Arg::new("search_zip").short('z').long("search-zip"));

    let test_args = &[
        vec!["reproducer", "-pz", "-p"],
        vec!["reproducer", "-pzp"],
        vec!["reproducer", "-zpp"],
        vec!["reproducer", "-pp", "-z"],
        vec!["reproducer", "-p", "-p", "-z"],
        vec!["reproducer", "-p", "-pz"],
        vec!["reproducer", "-ppz"],
    ];

    for argv in test_args {
        let _ = schema.clone().try_get_matches_from(argv).unwrap();
    }
}
<|endoftext|>


<commit_before>pub mod options {
  use super::*;

  {{#each protocol.classes as |class| ~}}
  {{#each class.methods as |method| ~}}
  {{#unless method.ignore_args ~}}
  {{#each_argument method.arguments as |argument| ~}}
  {{#unless @argument_is_value ~}}
  {{#unless argument.ignore_flags ~}}
  #[derive(Copy, Clone, Debug, Default, PartialEq)]
  pub struct {{camel class.name}}{{camel method.name}}Options {
    {{#each argument.flags as |flag| ~}}
    pub {{snake flag.name}}: Boolean,
    {{/each ~}}
  }

  {{/unless ~}}
  {{/unless ~}}
  {{/each_argument ~}}
  {{/unless ~}}
  {{/each ~}}
  {{/each ~}}
}

use options::*;

#[derive(Debug)]
#[allow(clippy::enum_variant_names)]
pub(crate) enum Reply {
  {{#each protocol.classes as |class| ~}}
  {{#each class.methods as |method| ~}}
  {{#if method.c2s ~}}
  {{#if method.synchronous ~}}
  {{camel class.name}}{{camel method.name}}Ok(PromiseResolver<{{#if method.metadata.confirmation.type ~}}{{method.metadata.confirmation.type}}{{else}}(){{/if ~}}>{{#each method.metadata.state as |state| ~}}, {{state.type}}{{/each ~}}),
  {{/if ~}}
  {{/if ~}}
  {{/each ~}}
  {{/each ~}}
}

impl Channel {
  pub(crate) fn receive_method(&self, method: AMQPClass) -> Result<()> {
    match method {
      {{#each protocol.classes as |class| ~}}
      {{#each class.methods as |method| ~}}
      {{#unless method.metadata.skip ~}}
      {{#if method.s2c ~}}
      AMQPClass::{{camel class.name}}(protocol::{{snake class.name}}::AMQPMethod::{{camel method.name}}(m)) => self.receive_{{snake class.name false}}_{{snake method.name false}}(m),
      {{/if ~}}
      {{/unless ~}}
      {{/each ~}}
      {{/each ~}}
      m => {
        error!("the client should not receive this method: {:?}", m);
        self.handle_invalid_contents(format!("unexepcted method received on channel {}", self.id), m.get_amqp_class_id(), m.get_amqp_method_id())
      }
    }
  }

  {{#each protocol.classes as |class| ~}}
  {{#each class.methods as |method| ~}}
  {{#unless method.metadata.skip ~}}
  {{#if method.c2s ~}}
  #[allow(clippy::too_many_arguments)]
  {{#unless method.metadata.require_wrapper ~}}{{#if method.is_reply ~}}{{#if method.metadata.internal ~}}pub(crate) {{/if ~}}{{else}}pub {{#if method.metadata.internal ~}}(crate) {{/if ~}}{{/if ~}}fn {{else}}fn do_{{/unless ~}}{{snake class.name false}}_{{snake method.name false}}(&self{{#unless method.ignore_args ~}}{{#each_argument method.arguments as |argument| ~}}{{#if @argument_is_value ~}}{{#unless argument.force_default ~}}, {{snake argument.name}}: {{#if (use_str_ref argument.type) ~}}&str{{else}}{{argument.type}}{{/if ~}}{{/unless ~}}{{else}}{{#unless argument.ignore_flags ~}}, options: {{camel class.name}}{{camel method.name}}Options{{/unless ~}}{{/if ~}}{{/each_argument ~}}{{/unless ~}}{{#each method.metadata.extra_args as |arg| ~}}, {{arg.name}}: {{arg.type}}{{/each ~}}) -> Promise{{#if method.metadata.confirmation.type ~}}Chain{{/if ~}}<{{#if method.metadata.confirmation.type ~}}{{method.metadata.confirmation.type}}{{else}}(){{/if ~}}> {
    {{#if method.metadata.channel_init ~}}
    if !self.status.initializing() {
    {{else}}
    {{#if method.metadata.channel_deinit ~}}
    if !self.status.closing() {
    {{else}}
    if !self.status.connected() {
    {{/if ~}}
    {{/if ~}}
      return Promise{{#if method.metadata.confirmation.type ~}}Chain{{/if ~}}::new_with_data(Err(Error::InvalidChannelState(self.status.state())));
    }

    {{#if method.metadata.start_hook ~}}
    {{#if method.metadata.start_hook.returns ~}}let start_hook_res = {{/if ~}}self.before_{{snake class.name false}}_{{snake method.name false}}({{#each method.metadata.start_hook.params as |param| ~}}{{#unless @first ~}}, {{/unless ~}}{{param}}{{/each ~}});
    {{/if ~}}

    {{#unless method.ignore_args ~}}
    {{#each_argument method.arguments as |argument| ~}}
    {{#unless @argument_is_value ~}}
    {{#unless argument.ignore_flags ~}}
    let {{camel class.name}}{{camel method.name}}Options {
      {{#each argument.flags as |flag| ~}}
      {{snake flag.name}}{{#if flag.force_default ~}}: _{{/if ~}},
      {{/each ~}}
    } = options;
    {{/unless ~}}
    {{/unless ~}}
    {{/each_argument ~}}
    {{/unless ~}}

    let method = AMQPClass::{{camel class.name}}(protocol::{{snake class.name}}::AMQPMethod::{{camel method.name}} (protocol::{{snake class.name}}::{{camel method.name}} {
      {{#each_argument method.arguments as |argument| ~}}
      {{#if @argument_is_value ~}}
      {{#unless argument.force_default ~}}
      {{snake argument.name}}: {{snake argument.name}}{{#if (use_str_ref argument.type) ~}}.into(){{/if ~}},
      {{/unless ~}}
      {{else}}
      {{#unless argument.ignore_flags ~}}
      {{#each argument.flags as |flag| ~}}
      {{#unless flag.force_default ~}}
      {{snake flag.name}},
      {{/unless ~}}
      {{/each ~}}
      {{/unless ~}}
      {{/if ~}}
      {{/each_argument ~}}
    }));

    {{#if method.metadata.carry_headers ~}}
    self.send_method_frame_with_body(method, payload, properties, start_hook_res).unwrap_or_else(|err| PromiseChain::new_with_data(Err(err)))
    {{else}}
    let (promise, send_resolver) = Promise::new();
    if log_enabled!(Trace) {
      promise.set_marker("{{class.name}}.{{method.name}}".into());
    }
    {{#if method.synchronous ~}}
    let (promise, resolver) = Promise{{#if method.metadata.confirmation.type ~}}Chain{{/if ~}}::after(promise);
    if log_enabled!(Trace) {
      promise.set_marker("{{class.name}}.{{method.name}}.Ok".into());
    }
    {{/if ~}}
    self.send_method_frame(method, send_resolver, {{#if method.synchronous ~}}Some(ExpectedReply(Reply::{{camel class.name}}{{camel method.name}}Ok(resolver.clone(){{#each method.metadata.state as |state| ~}}, {{state.name}}{{#if state.use_str_ref ~}}.into(){{/if ~}}{{/each ~}}), Box::new(resolver))){{else}}None{{/if ~}});
    {{#if method.metadata.end_hook ~}}
    let end_hook_res = self.on_{{snake class.name false}}_{{snake method.name false}}_sent({{#each method.metadata.end_hook.params as |param| ~}}{{#unless @first ~}}, {{/unless ~}}{{param}}{{/each ~}});
    if let Err(err) = end_hook_res {
      return Promise{{#if method.metadata.confirmation.type ~}}Chain{{/if ~}}::new_with_data(Err(err));
    }
    {{/if ~}}

    {{#if method.synchronous ~}}
    {{#if method.metadata.nowait_hook ~}}
    if nowait {
      if let Err(err) = self.receive_{{snake class.name false}}_{{snake method.name false}}_ok(protocol::{{snake class.name}}::{{camel method.name}}Ok { {{#each method.metadata.nowait_hook.fields as |field| ~}}{{field}}, {{/each ~}}{{#unless method.metadata.nowait_hook.exhaustive_args ~}}..Default::default(){{/unless ~}} }) {
        return Promise{{#if method.metadata.confirmation.type ~}}Chain{{/if ~}}::new_with_data(Err(err));
      }
    }
    {{/if ~}}
    {{/if ~}}
    promise
    {{/if ~}}
  }
  {{/if ~}}

  {{#if method.s2c ~}}
  {{#if method.is_reply ~}}
  fn receive_{{snake class.name false}}_{{snake method.name false}}(&self, method: protocol::{{snake class.name}}::{{camel method.name}}) -> Result<()> {
    {{#if class.metadata.channel0_only ~}}
    self.assert_channel0(
      method.get_amqp_class_id(),
      method.get_amqp_method_id(),
    )?;
    {{/if ~}}
    {{#if method.metadata.channel_init ~}}
    if !self.status.initializing() {
    {{else}}
    if !self.status.can_receive_messages() {
    {{/if ~}}
      return Err(Error::InvalidChannelState(self.status.state()));
    }

    match self.frames.next_expected_reply(self.id) {
      Some(Reply::{{camel class.name}}{{camel method.name}}(resolver{{#each method.metadata.state as |state| ~}}, {{state.name}}{{/each ~}})) => {
        {{#unless method.metadata.confirmation.type ~}}let res ={{/unless ~}}
        {{#if method.arguments ~}}
        self.on_{{snake class.name false}}_{{snake method.name false}}_received(method{{#if method.metadata.confirmation.type ~}}, resolver{{/if ~}}{{#each method.metadata.state as |state| ~}}, {{state.name}}{{/each ~}})
        {{else}}
        {{#if method.metadata.received_hook ~}}
        self.on_{{snake class.name false}}_{{snake method.name false}}_received({{#each method.metadata.received_hook.params as |param| ~}}{{#unless @first ~}}, {{/unless ~}}{{param}}{{/each ~}})
        {{else}}
        Ok(())
        {{/if ~}}
        {{/if ~}}
        {{#unless method.metadata.confirmation.type ~}};
        resolver.swear(res.clone());
        res
        {{/unless ~}}
      },
      _ => {
        self.handle_invalid_contents(format!("unexepcted {{class.name}} {{method.name}} received on channel {}", self.id), method.get_amqp_class_id(), method.get_amqp_method_id())
      },
    }
  }
  {{else}}
  fn receive_{{snake class.name false}}_{{snake method.name false}}(&self, method: protocol::{{snake class.name}}::{{camel method.name}}) -> Result<()> {
    {{#if class.metadata.channel0_only ~}}
    self.assert_channel0(
      method.get_amqp_class_id(),
      method.get_amqp_method_id(),
    )?;
    {{/if ~}}
    if !self.status.can_receive_messages() {
      return Err(Error::InvalidChannelState(self.status.state()));
    }
    self.on_{{snake class.name false}}_{{snake method.name false}}_received(method)
  }
  {{/if ~}}
  {{/if ~}}
  {{/unless ~}}
  {{/each ~}}
  {{/each ~}}
}
<commit_msg>use include_more<commit_after>pub mod options {
  use super::*;

  {{#each protocol.classes as |class| ~}}
  {{#each class.methods as |method| ~}}
  {{#unless method.ignore_args ~}}
  {{#each_argument method.arguments as |argument| ~}}
  {{#unless @argument_is_value ~}}
  {{#unless argument.ignore_flags ~}}
  #[derive(Copy, Clone, Debug, Default, PartialEq)]
  pub struct {{camel class.name}}{{camel method.name}}Options {
    {{#each argument.flags as |flag| ~}}
    pub {{snake flag.name}}: Boolean,
    {{/each ~}}
  }

  {{/unless ~}}
  {{/unless ~}}
  {{/each_argument ~}}
  {{/unless ~}}
  {{/each ~}}
  {{/each ~}}
}

use options::*;

#[derive(Debug)]
#[allow(clippy::enum_variant_names)]
pub(crate) enum Reply {
  {{#each protocol.classes as |class| ~}}
  {{#each class.methods as |method| ~}}
  {{#if method.c2s ~}}
  {{#if method.synchronous ~}}
  {{camel class.name}}{{camel method.name}}Ok(PromiseResolver<{{#if method.metadata.confirmation.type ~}}{{method.metadata.confirmation.type}}{{else}}(){{/if ~}}>{{#each method.metadata.state as |state| ~}}, {{state.type}}{{/each ~}}),
  {{/if ~}}
  {{/if ~}}
  {{/each ~}}
  {{/each ~}}
}

impl Channel {
  pub(crate) fn receive_method(&self, method: AMQPClass) -> Result<()> {
    match method {
      {{#each protocol.classes as |class| ~}}
      {{#each class.methods as |method| ~}}
      {{#unless method.metadata.skip ~}}
      {{#if method.s2c ~}}
      AMQPClass::{{camel class.name}}(protocol::{{snake class.name}}::AMQPMethod::{{camel method.name}}(m)) => self.receive_{{snake class.name false}}_{{snake method.name false}}(m),
      {{/if ~}}
      {{/unless ~}}
      {{/each ~}}
      {{/each ~}}
      m => {
        error!("the client should not receive this method: {:?}", m);
        self.handle_invalid_contents(format!("unexepcted method received on channel {}", self.id), m.get_amqp_class_id(), m.get_amqp_method_id())
      }
    }
  }

  {{#each protocol.classes as |class| ~}}
  {{#each class.methods as |method| ~}}
  {{#unless method.metadata.skip ~}}
  {{#if method.c2s ~}}
#[allow(clippy::too_many_arguments)]
{{include_more class.name method.name}}{{#unless method.metadata.require_wrapper ~}}{{#if method.is_reply ~}}{{#if method.metadata.internal ~}}pub(crate) {{/if ~}}{{else}}pub {{#if method.metadata.internal ~}}(crate) {{/if ~}}{{/if ~}}fn {{else}}fn do_{{/unless ~}}{{snake class.name false}}_{{snake method.name false}}(&self{{#unless method.ignore_args ~}}{{#each_argument method.arguments as |argument| ~}}{{#if @argument_is_value ~}}{{#unless argument.force_default ~}}, {{snake argument.name}}: {{#if (use_str_ref argument.type) ~}}&str{{else}}{{argument.type}}{{/if ~}}{{/unless ~}}{{else}}{{#unless argument.ignore_flags ~}}, options: {{camel class.name}}{{camel method.name}}Options{{/unless ~}}{{/if ~}}{{/each_argument ~}}{{/unless ~}}{{#each method.metadata.extra_args as |arg| ~}}, {{arg.name}}: {{arg.type}}{{/each ~}}) -> Promise{{#if method.metadata.confirmation.type ~}}Chain{{/if ~}}<{{#if method.metadata.confirmation.type ~}}{{method.metadata.confirmation.type}}{{else}}(){{/if ~}}> {
    {{#if method.metadata.channel_init ~}}
    if !self.status.initializing() {
    {{else}}
    {{#if method.metadata.channel_deinit ~}}
    if !self.status.closing() {
    {{else}}
    if !self.status.connected() {
    {{/if ~}}
    {{/if ~}}
      return Promise{{#if method.metadata.confirmation.type ~}}Chain{{/if ~}}::new_with_data(Err(Error::InvalidChannelState(self.status.state())));
    }

    {{#if method.metadata.start_hook ~}}
    {{#if method.metadata.start_hook.returns ~}}let start_hook_res = {{/if ~}}self.before_{{snake class.name false}}_{{snake method.name false}}({{#each method.metadata.start_hook.params as |param| ~}}{{#unless @first ~}}, {{/unless ~}}{{param}}{{/each ~}});
    {{/if ~}}

    {{#unless method.ignore_args ~}}
    {{#each_argument method.arguments as |argument| ~}}
    {{#unless @argument_is_value ~}}
    {{#unless argument.ignore_flags ~}}
    let {{camel class.name}}{{camel method.name}}Options {
      {{#each argument.flags as |flag| ~}}
      {{snake flag.name}}{{#if flag.force_default ~}}: _{{/if ~}},
      {{/each ~}}
    } = options;
    {{/unless ~}}
    {{/unless ~}}
    {{/each_argument ~}}
    {{/unless ~}}

    let method = AMQPClass::{{camel class.name}}(protocol::{{snake class.name}}::AMQPMethod::{{camel method.name}} (protocol::{{snake class.name}}::{{camel method.name}} {
      {{#each_argument method.arguments as |argument| ~}}
      {{#if @argument_is_value ~}}
      {{#unless argument.force_default ~}}
      {{snake argument.name}}: {{snake argument.name}}{{#if (use_str_ref argument.type) ~}}.into(){{/if ~}},
      {{/unless ~}}
      {{else}}
      {{#unless argument.ignore_flags ~}}
      {{#each argument.flags as |flag| ~}}
      {{#unless flag.force_default ~}}
      {{snake flag.name}},
      {{/unless ~}}
      {{/each ~}}
      {{/unless ~}}
      {{/if ~}}
      {{/each_argument ~}}
    }));

    {{#if method.metadata.carry_headers ~}}
    self.send_method_frame_with_body(method, payload, properties, start_hook_res).unwrap_or_else(|err| PromiseChain::new_with_data(Err(err)))
    {{else}}
    let (promise, send_resolver) = Promise::new();
    if log_enabled!(Trace) {
      promise.set_marker("{{class.name}}.{{method.name}}".into());
    }
    {{#if method.synchronous ~}}
    let (promise, resolver) = Promise{{#if method.metadata.confirmation.type ~}}Chain{{/if ~}}::after(promise);
    if log_enabled!(Trace) {
      promise.set_marker("{{class.name}}.{{method.name}}.Ok".into());
    }
    {{/if ~}}
    self.send_method_frame(method, send_resolver, {{#if method.synchronous ~}}Some(ExpectedReply(Reply::{{camel class.name}}{{camel method.name}}Ok(resolver.clone(){{#each method.metadata.state as |state| ~}}, {{state.name}}{{#if state.use_str_ref ~}}.into(){{/if ~}}{{/each ~}}), Box::new(resolver))){{else}}None{{/if ~}});
    {{#if method.metadata.end_hook ~}}
    let end_hook_res = self.on_{{snake class.name false}}_{{snake method.name false}}_sent({{#each method.metadata.end_hook.params as |param| ~}}{{#unless @first ~}}, {{/unless ~}}{{param}}{{/each ~}});
    if let Err(err) = end_hook_res {
      return Promise{{#if method.metadata.confirmation.type ~}}Chain{{/if ~}}::new_with_data(Err(err));
    }
    {{/if ~}}

    {{#if method.synchronous ~}}
    {{#if method.metadata.nowait_hook ~}}
    if nowait {
      if let Err(err) = self.receive_{{snake class.name false}}_{{snake method.name false}}_ok(protocol::{{snake class.name}}::{{camel method.name}}Ok { {{#each method.metadata.nowait_hook.fields as |field| ~}}{{field}}, {{/each ~}}{{#unless method.metadata.nowait_hook.exhaustive_args ~}}..Default::default(){{/unless ~}} }) {
        return Promise{{#if method.metadata.confirmation.type ~}}Chain{{/if ~}}::new_with_data(Err(err));
      }
    }
    {{/if ~}}
    {{/if ~}}
    promise
    {{/if ~}}
  }
  {{/if ~}}

  {{#if method.s2c ~}}
  {{#if method.is_reply ~}}
  fn receive_{{snake class.name false}}_{{snake method.name false}}(&self, method: protocol::{{snake class.name}}::{{camel method.name}}) -> Result<()> {
    {{#if class.metadata.channel0_only ~}}
    self.assert_channel0(
      method.get_amqp_class_id(),
      method.get_amqp_method_id(),
    )?;
    {{/if ~}}
    {{#if method.metadata.channel_init ~}}
    if !self.status.initializing() {
    {{else}}
    if !self.status.can_receive_messages() {
    {{/if ~}}
      return Err(Error::InvalidChannelState(self.status.state()));
    }

    match self.frames.next_expected_reply(self.id) {
      Some(Reply::{{camel class.name}}{{camel method.name}}(resolver{{#each method.metadata.state as |state| ~}}, {{state.name}}{{/each ~}})) => {
        {{#unless method.metadata.confirmation.type ~}}let res ={{/unless ~}}
        {{#if method.arguments ~}}
        self.on_{{snake class.name false}}_{{snake method.name false}}_received(method{{#if method.metadata.confirmation.type ~}}, resolver{{/if ~}}{{#each method.metadata.state as |state| ~}}, {{state.name}}{{/each ~}})
        {{else}}
        {{#if method.metadata.received_hook ~}}
        self.on_{{snake class.name false}}_{{snake method.name false}}_received({{#each method.metadata.received_hook.params as |param| ~}}{{#unless @first ~}}, {{/unless ~}}{{param}}{{/each ~}})
        {{else}}
        Ok(())
        {{/if ~}}
        {{/if ~}}
        {{#unless method.metadata.confirmation.type ~}};
        resolver.swear(res.clone());
        res
        {{/unless ~}}
      },
      _ => {
        self.handle_invalid_contents(format!("unexepcted {{class.name}} {{method.name}} received on channel {}", self.id), method.get_amqp_class_id(), method.get_amqp_method_id())
      },
    }
  }
  {{else}}
  fn receive_{{snake class.name false}}_{{snake method.name false}}(&self, method: protocol::{{snake class.name}}::{{camel method.name}}) -> Result<()> {
    {{#if class.metadata.channel0_only ~}}
    self.assert_channel0(
      method.get_amqp_class_id(),
      method.get_amqp_method_id(),
    )?;
    {{/if ~}}
    if !self.status.can_receive_messages() {
      return Err(Error::InvalidChannelState(self.status.state()));
    }
    self.on_{{snake class.name false}}_{{snake method.name false}}_received(method)
  }
  {{/if ~}}
  {{/if ~}}
  {{/unless ~}}
  {{/each ~}}
  {{/each ~}}
}
<|endoftext|>


<commit_before>///! Reference counter for channels.

use std::isize;
use std::ops;
use std::process;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};

/// Reference counter internals.
struct Counter<C> {
    /// The number of senders associated with the channel.
    senders: AtomicUsize,

    /// The number of receivers associated with the channel.
    receivers: AtomicUsize,

    /// Set to `true` if the last sender or the last receiver reference deallocates the channel.
    destroy: AtomicBool,

    /// The internal channel.
    chan: C,
}

/// Wraps a channel into the reference counter.
pub fn new<C>(chan: C) -> (Sender<C>, Receiver<C>) {
    let counter = Box::into_raw(Box::new(Counter {
        senders: AtomicUsize::new(1),
        receivers: AtomicUsize::new(1),
        destroy: AtomicBool::new(false),
        chan,
    }));
    let s = Sender { counter };
    let r = Receiver { counter };
    (s, r)
}

/// The sending side.
pub struct Sender<C> {
    counter: *mut Counter<C>,
}

impl<C> Sender<C> {
    /// Returns the internal `Counter`.
    fn counter(&self) -> &Counter<C> {
        unsafe { &*self.counter }
    }

    /// Acquires another sender reference.
    pub fn acquire(&self) -> Sender<C> {
        let count = self.counter().senders.fetch_add(1, Ordering::Relaxed);

        // Cloning senders and calling `mem::forget` on the clones could potentially overflow the
        // counter. It's very difficult to recover sensibly from such degenerate scenarios so we
        // just abort when the count becomes very large.
        if count > isize::MAX as usize {
            process::abort();
        }

        Sender {
            counter: self.counter,
        }
    }

    /// Releases the sender reference.
    ///
    /// Function `disconnect` will be called if this is the last sender reference.
    pub unsafe fn release<F: FnOnce(&C) -> bool>(&self, disconnect: F) {
        if self.counter().senders.fetch_sub(1, Ordering::AcqRel) == 1 {
            disconnect(&self.counter().chan);

            if self.counter().destroy.swap(true, Ordering::AcqRel) {
                drop(Box::from_raw(self.counter));
            }
        }
    }
}

impl<C> ops::Deref for Sender<C> {
    type Target = C;

    fn deref(&self) -> &C {
        &self.counter().chan
    }
}

impl<C> PartialEq for Sender<C> {
    fn eq(&self, other: &Sender<C>) -> bool {
        self.counter == other.counter
    }
}

/// The receiving side.
pub struct Receiver<C> {
    counter: *mut Counter<C>,
}

impl<C> Receiver<C> {
    /// Returns the internal `Counter`.
    fn counter(&self) -> &Counter<C> {
        unsafe { &*self.counter }
    }

    /// Acquires another receiver reference.
    pub fn acquire(&self) -> Receiver<C> {
        let count = self.counter().receivers.fetch_add(1, Ordering::Relaxed);

        // Cloning receivers and calling `mem::forget` on the clones could potentially overflow the
        // counter. It's very difficult to recover sensibly from such degenerate scenarios so we
        // just abort when the count becomes very large.
        if count > isize::MAX as usize {
            process::abort();
        }

        Receiver {
            counter: self.counter,
        }
    }

    /// Releases the receiver reference.
    ///
    /// Function `disconnect` will be called if this is the last receiver reference.
    pub unsafe fn release<F: FnOnce(&C) -> bool>(&self, disconnect: F) {
        if self.counter().receivers.fetch_sub(1, Ordering::AcqRel) == 1 {
            disconnect(&self.counter().chan);

            if self.counter().destroy.swap(true, Ordering::AcqRel) {
                drop(Box::from_raw(self.counter));
            }
        }
    }
}

impl<C> ops::Deref for Receiver<C> {
    type Target = C;

    fn deref(&self) -> &C {
        &self.counter().chan
    }
}

impl<C> PartialEq for Receiver<C> {
    fn eq(&self, other: &Receiver<C>) -> bool {
        self.counter == other.counter
    }
}
<commit_msg>Formatting<commit_after>//! Reference counter for channels.

use std::isize;
use std::ops;
use std::process;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};

/// Reference counter internals.
struct Counter<C> {
    /// The number of senders associated with the channel.
    senders: AtomicUsize,

    /// The number of receivers associated with the channel.
    receivers: AtomicUsize,

    /// Set to `true` if the last sender or the last receiver reference deallocates the channel.
    destroy: AtomicBool,

    /// The internal channel.
    chan: C,
}

/// Wraps a channel into the reference counter.
pub fn new<C>(chan: C) -> (Sender<C>, Receiver<C>) {
    let counter = Box::into_raw(Box::new(Counter {
        senders: AtomicUsize::new(1),
        receivers: AtomicUsize::new(1),
        destroy: AtomicBool::new(false),
        chan,
    }));
    let s = Sender { counter };
    let r = Receiver { counter };
    (s, r)
}

/// The sending side.
pub struct Sender<C> {
    counter: *mut Counter<C>,
}

impl<C> Sender<C> {
    /// Returns the internal `Counter`.
    fn counter(&self) -> &Counter<C> {
        unsafe { &*self.counter }
    }

    /// Acquires another sender reference.
    pub fn acquire(&self) -> Sender<C> {
        let count = self.counter().senders.fetch_add(1, Ordering::Relaxed);

        // Cloning senders and calling `mem::forget` on the clones could potentially overflow the
        // counter. It's very difficult to recover sensibly from such degenerate scenarios so we
        // just abort when the count becomes very large.
        if count > isize::MAX as usize {
            process::abort();
        }

        Sender {
            counter: self.counter,
        }
    }

    /// Releases the sender reference.
    ///
    /// Function `disconnect` will be called if this is the last sender reference.
    pub unsafe fn release<F: FnOnce(&C) -> bool>(&self, disconnect: F) {
        if self.counter().senders.fetch_sub(1, Ordering::AcqRel) == 1 {
            disconnect(&self.counter().chan);

            if self.counter().destroy.swap(true, Ordering::AcqRel) {
                drop(Box::from_raw(self.counter));
            }
        }
    }
}

impl<C> ops::Deref for Sender<C> {
    type Target = C;

    fn deref(&self) -> &C {
        &self.counter().chan
    }
}

impl<C> PartialEq for Sender<C> {
    fn eq(&self, other: &Sender<C>) -> bool {
        self.counter == other.counter
    }
}

/// The receiving side.
pub struct Receiver<C> {
    counter: *mut Counter<C>,
}

impl<C> Receiver<C> {
    /// Returns the internal `Counter`.
    fn counter(&self) -> &Counter<C> {
        unsafe { &*self.counter }
    }

    /// Acquires another receiver reference.
    pub fn acquire(&self) -> Receiver<C> {
        let count = self.counter().receivers.fetch_add(1, Ordering::Relaxed);

        // Cloning receivers and calling `mem::forget` on the clones could potentially overflow the
        // counter. It's very difficult to recover sensibly from such degenerate scenarios so we
        // just abort when the count becomes very large.
        if count > isize::MAX as usize {
            process::abort();
        }

        Receiver {
            counter: self.counter,
        }
    }

    /// Releases the receiver reference.
    ///
    /// Function `disconnect` will be called if this is the last receiver reference.
    pub unsafe fn release<F: FnOnce(&C) -> bool>(&self, disconnect: F) {
        if self.counter().receivers.fetch_sub(1, Ordering::AcqRel) == 1 {
            disconnect(&self.counter().chan);

            if self.counter().destroy.swap(true, Ordering::AcqRel) {
                drop(Box::from_raw(self.counter));
            }
        }
    }
}

impl<C> ops::Deref for Receiver<C> {
    type Target = C;

    fn deref(&self) -> &C {
        &self.counter().chan
    }
}

impl<C> PartialEq for Receiver<C> {
    fn eq(&self, other: &Receiver<C>) -> bool {
        self.counter == other.counter
    }
}
<|endoftext|>


<commit_before>use bytes::Buf;
use bytes::Bytes;

// TODO: some tests
#[derive(Default)]
pub struct WriteBuffer {
    data: Vec<u8>,
    position: usize, // must be `<= data.len()`
}

impl Buf for WriteBuffer {
    /// Size of data in the buffer
    fn remaining(&self) -> usize {
        debug_assert!(self.position <= self.data.len());
        self.data.len() - self.position
    }

    fn bytes(&self) -> &[u8] {
        &self.data[self.position..]
    }

    fn advance(&mut self, cnt: usize) {
        assert!(cnt <= self.remaining());
        self.position += cnt;
    }
}

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

    pub fn reserve(&mut self, additional: usize) {
        if self.remaining() >= additional {
            return;
        }
        self.compact();
        self.data.reserve(additional);
    }

    fn compact(&mut self) {
        self.data.drain(..self.position);
        self.position = 0;
    }

    pub fn extend_from_slice(&mut self, data: &[u8]) {
        // Could do something smarter
        self.reserve(data.len());
        self.data.extend_from_slice(data);
    }

    pub fn extend_from_vec(&mut self, data: Vec<u8>) {
        self.extend_from_slice(&data);
    }

    pub fn extend_from_bytes(&mut self, data: Bytes) {
        self.extend_from_slice(&data);
    }

    pub fn extend_from_bytes_ref(&mut self, data: &Bytes) {
        self.extend_from_slice(&*data);
    }

    pub fn extend_from_iter(&mut self, iter: impl Iterator<Item = u8>) {
        // Could do something smarter
        self.compact();
        self.data.extend(iter);
    }

    pub fn tail_vec(&mut self) -> WriteBufferTailVec {
        WriteBufferTailVec {
            data: &mut self.data,
            position: &mut self.position,
        }
    }
}

impl Into<Vec<u8>> for WriteBuffer {
    fn into(mut self) -> Vec<u8> {
        self.compact();
        self.data
    }
}

impl Into<Bytes> for WriteBuffer {
    fn into(self) -> Bytes {
        Bytes::from(Into::<Vec<u8>>::into(self))
    }
}

pub struct WriteBufferTailVec<'a> {
    data: &'a mut Vec<u8>,
    position: &'a mut usize,
}

impl<'a> WriteBufferTailVec<'a> {
    /// Size of data in the buffer
    pub fn remaining(&self) -> usize {
        debug_assert!(*self.position <= self.data.len());
        self.data.len() - *self.position
    }

    /// Pos is relative to "data"
    pub fn patch_buf(&mut self, pos: usize, data: &[u8]) {
        let patch_pos = *self.position + pos;
        (&mut self.data[patch_pos..patch_pos + data.len()]).copy_from_slice(data);
    }

    pub fn extend_from_slice(&mut self, data: &[u8]) {
        // Could do something smarter
        self.reserve(data.len());
        self.data.extend_from_slice(data);
    }

    pub fn reserve(&mut self, additional: usize) {
        if self.remaining() >= additional {
            return;
        }
        self.compact();
        self.data.reserve(additional);
    }

    pub fn compact(&mut self) {
        self.data.drain(..*self.position);
        *self.position = 0;
    }
}

impl<'a> Drop for WriteBufferTailVec<'a> {
    fn drop(&mut self) {}
}

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

    #[test]
    fn remaining() {
        let mut buf = WriteBuffer::new();
        buf.extend_from_slice(b"abcd");
        assert_eq!(4, buf.remaining());

        assert_eq!(b'a', buf.get_u8());
        assert_eq!(b'b', buf.get_u8());
        assert_eq!(2, buf.remaining());

        buf.extend_from_slice(b"ef");
        assert_eq!(b'c', buf.get_u8());
        assert_eq!(b'd', buf.get_u8());
        assert_eq!(b'e', buf.get_u8());
        assert_eq!(b'f', buf.get_u8());
        assert_eq!(0, buf.remaining());
    }
}
<commit_msg>Dead code<commit_after>use bytes::Buf;
use bytes::Bytes;

// TODO: some tests
#[derive(Default)]
pub struct WriteBuffer {
    data: Vec<u8>,
    position: usize, // must be `<= data.len()`
}

impl Buf for WriteBuffer {
    /// Size of data in the buffer
    fn remaining(&self) -> usize {
        debug_assert!(self.position <= self.data.len());
        self.data.len() - self.position
    }

    fn bytes(&self) -> &[u8] {
        &self.data[self.position..]
    }

    fn advance(&mut self, cnt: usize) {
        assert!(cnt <= self.remaining());
        self.position += cnt;
    }
}

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

    pub fn reserve(&mut self, additional: usize) {
        if self.remaining() >= additional {
            return;
        }
        self.compact();
        self.data.reserve(additional);
    }

    fn compact(&mut self) {
        self.data.drain(..self.position);
        self.position = 0;
    }

    pub fn extend_from_slice(&mut self, data: &[u8]) {
        // Could do something smarter
        self.reserve(data.len());
        self.data.extend_from_slice(data);
    }

    pub fn extend_from_vec(&mut self, data: Vec<u8>) {
        self.extend_from_slice(&data);
    }

    pub fn extend_from_bytes(&mut self, data: Bytes) {
        self.extend_from_slice(&data);
    }

    pub fn extend_from_bytes_ref(&mut self, data: &Bytes) {
        self.extend_from_slice(&*data);
    }

    pub fn tail_vec(&mut self) -> WriteBufferTailVec {
        WriteBufferTailVec {
            data: &mut self.data,
            position: &mut self.position,
        }
    }
}

impl Into<Vec<u8>> for WriteBuffer {
    fn into(mut self) -> Vec<u8> {
        self.compact();
        self.data
    }
}

impl Into<Bytes> for WriteBuffer {
    fn into(self) -> Bytes {
        Bytes::from(Into::<Vec<u8>>::into(self))
    }
}

pub struct WriteBufferTailVec<'a> {
    data: &'a mut Vec<u8>,
    position: &'a mut usize,
}

impl<'a> WriteBufferTailVec<'a> {
    /// Size of data in the buffer
    pub fn remaining(&self) -> usize {
        debug_assert!(*self.position <= self.data.len());
        self.data.len() - *self.position
    }

    /// Pos is relative to "data"
    pub fn patch_buf(&mut self, pos: usize, data: &[u8]) {
        let patch_pos = *self.position + pos;
        (&mut self.data[patch_pos..patch_pos + data.len()]).copy_from_slice(data);
    }

    pub fn extend_from_slice(&mut self, data: &[u8]) {
        // Could do something smarter
        self.reserve(data.len());
        self.data.extend_from_slice(data);
    }

    pub fn reserve(&mut self, additional: usize) {
        if self.remaining() >= additional {
            return;
        }
        self.compact();
        self.data.reserve(additional);
    }

    pub fn compact(&mut self) {
        self.data.drain(..*self.position);
        *self.position = 0;
    }
}

impl<'a> Drop for WriteBufferTailVec<'a> {
    fn drop(&mut self) {}
}

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

    #[test]
    fn remaining() {
        let mut buf = WriteBuffer::new();
        buf.extend_from_slice(b"abcd");
        assert_eq!(4, buf.remaining());

        assert_eq!(b'a', buf.get_u8());
        assert_eq!(b'b', buf.get_u8());
        assert_eq!(2, buf.remaining());

        buf.extend_from_slice(b"ef");
        assert_eq!(b'c', buf.get_u8());
        assert_eq!(b'd', buf.get_u8());
        assert_eq!(b'e', buf.get_u8());
        assert_eq!(b'f', buf.get_u8());
        assert_eq!(0, buf.remaining());
    }
}
<|endoftext|>


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

//! Local state for keys in the snapshot in progress (the "index").

use diesel;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;

use std::sync::mpsc;
use time::Duration;

use blob;
use hash;
use periodic_timer::PeriodicTimer;
use process::{Process, MsgHandler};
use util;

use super::schema;

error_type! {
    #[derive(Debug)]
    pub enum MsgError {
        Recv(mpsc::RecvError) {
            cause;
        }
    }
}

#[derive(Clone, Debug)]
pub struct Entry {
    pub id: Option<u64>,
    pub parent_id: Option<u64>,

    pub name: Vec<u8>,

    pub created: Option<i64>,
    pub modified: Option<i64>,
    pub accessed: Option<i64>,

    pub permissions: Option<u64>,
    pub user_id: Option<u64>,
    pub group_id: Option<u64>,

    pub data_hash: Option<Vec<u8>>,
    pub data_length: Option<u64>,
}

pub type IndexProcess = Process<Msg, Reply>;

pub enum Msg {
    /// Insert an entry in the key index.
    /// Returns `Id` with the new entry ID.
    Insert(Entry),

    /// Lookup an entry in the key index by its parent id and name.
    /// Returns either `Entry` with the found entry or `NotFound`.
    Lookup(Option<u64>, Vec<u8>),

    /// Update the `payload` and `persistent_ref` of an entry.
    /// Returns `UpdateOk`.
    UpdateDataHash(Entry, Option<hash::Hash>, Option<blob::ChunkRef>),

    /// List a directory (aka. `level`) in the index.
    /// Returns `ListResult` with all the entries under the given parent.
    ListDir(Option<u64>),

    /// Flush this key index.
    Flush,
}

pub enum Reply {
    Entry(Entry),
    NotFound,
    UpdateOk,
    ListResult(Vec<(Entry, Option<blob::ChunkRef>)>),
    FlushOk,
}

pub struct Index {
    path: String,
    conn: SqliteConnection,
    flush_timer: PeriodicTimer,
}

fn i64_to_u64_or_panic(x: i64) -> u64 {
    if x < 0 {
        panic!("expected u64, got {:?}", x);
    }
    return x as u64;
}

impl Index {
    pub fn new(path: String) -> Index {
        let conn = SqliteConnection::establish(&path).expect("Could not open SQLite database");

        let ki = Index {
            path: path,
            conn: conn,
            flush_timer: PeriodicTimer::new(Duration::seconds(5)),
        };

        let dir = diesel::migrations::find_migrations_directory().unwrap();
        diesel::migrations::run_pending_migrations_in_directory(&ki.conn,
                                                                &dir,
                                                                &mut util::InfoWriter)
            .unwrap();
        ki.conn.begin_transaction().unwrap();

        ki
    }

    #[cfg(test)]
    pub fn new_for_testing() -> Index {
        Index::new(":memory:".to_string())
    }

    fn last_insert_rowid(&self) -> i64 {
        diesel::select(diesel::expression::sql("last_insert_rowid()"))
            .first::<i64>(&self.conn)
            .unwrap()
    }

    pub fn maybe_flush(&mut self) {
        if self.flush_timer.did_fire() {
            self.flush();
        }
    }

    pub fn flush(&mut self) {
        self.conn.commit_transaction().unwrap();
        self.conn.begin_transaction().unwrap();
    }
}

impl Clone for Index {
    fn clone(&self) -> Index {
        Index::new(self.path.clone())
    }
}

impl MsgHandler<Msg, Reply> for Index {
    type Err = MsgError;

    fn handle(&mut self, msg: Msg, reply: Box<Fn(Reply)>) -> Result<(), MsgError> {
        match msg {

            Msg::Insert(entry) => {
                use super::schema::keys::dsl::*;

                let entry = match entry.id {
                    Some(id_) => {
                        // Replace existing entry.
                        diesel::update(keys.find(id_ as i64))
                            .set((parent.eq(entry.parent_id.map(|x| x as i64)),
                                  name.eq(&entry.name[..]),
                                  created.eq(entry.created),
                                  modified.eq(entry.modified),
                                  accessed.eq(entry.accessed)))
                            .execute(&self.conn)
                            .expect("Error updating key");
                        entry
                    }
                    None => {
                        // Insert new entry.
                        {
                            let new = schema::NewKey {
                                parent: entry.parent_id.map(|x| x as i64),
                                name: &entry.name[..],
                                created: entry.created,
                                modified: entry.modified,
                                accessed: entry.accessed,
                                permissions: entry.permissions.map(|x| x as i64),
                                group_id: entry.group_id.map(|x| x as i64),
                                user_id: entry.user_id.map(|x| x as i64),
                                hash: None,
                                persistent_ref: None,
                            };

                            diesel::insert(&new)
                                .into(keys)
                                .execute(&self.conn)
                                .expect("Error inserting key");
                        }
                        let mut entry = entry;
                        entry.id = Some(self.last_insert_rowid() as u64);
                        entry
                    }
                };

                reply(Reply::Entry(entry));
            }

            Msg::Lookup(parent_, name_) => {
                use super::schema::keys::dsl::*;

                let row_opt = match parent_ {
                    Some(p) => {
                        keys.filter(parent.eq(p as i64))
                            .filter(name.eq(&name_[..]))
                            .first::<schema::Key>(&self.conn)
                            .optional()
                            .expect("Error searching keys")
                    }
                    None => {
                        keys.filter(parent.is_null())
                            .filter(name.eq(&name_[..]))
                            .first::<schema::Key>(&self.conn)
                            .optional()
                            .expect("Error searching keys")
                    }
                };

                if let Some(row) = row_opt {
                    reply(Reply::Entry(Entry {
                        id: Some(row.id as u64),
                        parent_id: parent_,
                        name: name_,
                        created: row.created,
                        modified: row.modified,
                        accessed: row.accessed,
                        permissions: row.permissions.map(|x| x as u64),
                        user_id: row.user_id.map(|x| x as u64),
                        group_id: row.group_id.map(|x| x as u64),
                        data_hash: row.hash,
                        data_length: None,
                    }));
                    return Ok(());
                }
                reply(Reply::NotFound);
            }

            Msg::UpdateDataHash(entry, hash_opt, persistent_ref_opt) => {
                use super::schema::keys::dsl::*;

                let id_ = entry.id.expect("Tried to update without an id") as i64;
                assert!(hash_opt.is_some() == persistent_ref_opt.is_some());

                let hash_bytes = hash_opt.map(|h| h.bytes);
                let persistent_ref_bytes = persistent_ref_opt.map(|p| p.as_bytes());

                if entry.modified.is_some() {
                    diesel::update(keys.find(id_)
                                       .filter(modified.eq::<Option<i64>>(None)
                                                       .or(modified.le(entry.modified))))
                        .set((hash.eq(hash_bytes), persistent_ref.eq(persistent_ref_bytes)))
                        .execute(&self.conn)
                        .expect("Error updating key");
                } else {
                    diesel::update(keys.find(id_))
                        .set((hash.eq(hash_bytes), persistent_ref.eq(persistent_ref_bytes)))
                        .execute(&self.conn)
                        .expect("Error updating key");
                }

                self.maybe_flush();
                reply(Reply::UpdateOk);
            }

            Msg::Flush => {
                self.flush();
                reply(Reply::FlushOk);
            }

            Msg::ListDir(parent_opt) => {
                use super::schema::keys::dsl::*;

                let rows = match parent_opt {
                    Some(p) => {
                        keys.filter(parent.eq(p as i64))
                            .load::<schema::Key>(&self.conn)
                            .expect("Error listing keys")
                    }
                    None => {
                        keys.filter(parent.is_null())
                            .load::<schema::Key>(&self.conn)
                            .expect("Error listing keys")
                    }
                };

                reply(Reply::ListResult(rows.into_iter()
                                                   .map(|mut r| {
                                                       (Entry {
                                                           id: Some(r.id as u64),
                                                           parent_id: r.parent.map(|x| x as u64),
                                                           name: r.name,
                                                           created: r.created,
                                                           modified: r.modified,
                                                           accessed: r.accessed,
                                                           permissions: r.permissions
                                                                         .map(|x| x as u64),
                                                           user_id: r.user_id.map(|x| x as u64),
                                                           group_id: r.group_id.map(|x| x as u64),
                                                           data_hash: r.hash,
                                                           data_length: None,
                                                       },
                                                        r.persistent_ref.as_mut().map(|p| {
                                                           blob::ChunkRef::from_bytes(&mut &p[..])
                                                               .unwrap()
                                                       }))
                                                   })
                                                   .collect()));
            }
        }

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

//! Local state for keys in the snapshot in progress (the "index").

use diesel;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;

use std::sync::mpsc;
use time::Duration;

use blob;
use hash;
use periodic_timer::PeriodicTimer;
use process::{Process, MsgHandler};
use util;

use super::schema;

error_type! {
    #[derive(Debug)]
    pub enum MsgError {
        Recv(mpsc::RecvError) {
            cause;
        }
    }
}

#[derive(Clone, Debug)]
pub struct Entry {
    pub id: Option<u64>,
    pub parent_id: Option<u64>,

    pub name: Vec<u8>,

    pub created: Option<i64>,
    pub modified: Option<i64>,
    pub accessed: Option<i64>,

    pub permissions: Option<u64>,
    pub user_id: Option<u64>,
    pub group_id: Option<u64>,

    pub data_hash: Option<Vec<u8>>,
    pub data_length: Option<u64>,
}

pub type IndexProcess = Process<Msg, Reply>;

pub enum Msg {
    /// Insert an entry in the key index.
    /// Returns `Id` with the new entry ID.
    Insert(Entry),

    /// Lookup an entry in the key index by its parent id and name.
    /// Returns either `Entry` with the found entry or `NotFound`.
    Lookup(Option<u64>, Vec<u8>),

    /// Update the `payload` and `persistent_ref` of an entry.
    /// Returns `UpdateOk`.
    UpdateDataHash(Entry, Option<hash::Hash>, Option<blob::ChunkRef>),

    /// List a directory (aka. `level`) in the index.
    /// Returns `ListResult` with all the entries under the given parent.
    ListDir(Option<u64>),

    /// Flush this key index.
    Flush,
}

pub enum Reply {
    Entry(Entry),
    NotFound,
    UpdateOk,
    ListResult(Vec<(Entry, Option<blob::ChunkRef>)>),
    FlushOk,
}

pub struct Index {
    path: String,
    conn: SqliteConnection,
    flush_timer: PeriodicTimer,
}

fn i64_to_u64_or_panic(x: i64) -> u64 {
    if x < 0 {
        panic!("expected u64, got {:?}", x);
    }
    return x as u64;
}

impl Index {
    pub fn new(path: String) -> Index {
        let conn = SqliteConnection::establish(&path).expect("Could not open SQLite database");

        let ki = Index {
            path: path,
            conn: conn,
            flush_timer: PeriodicTimer::new(Duration::seconds(5)),
        };

        let dir = diesel::migrations::find_migrations_directory().unwrap();
        diesel::migrations::run_pending_migrations_in_directory(&ki.conn,
                                                                &dir,
                                                                &mut util::InfoWriter)
            .unwrap();
        ki.conn.begin_transaction().unwrap();

        ki
    }

    #[cfg(test)]
    pub fn new_for_testing() -> Index {
        Index::new(":memory:".to_string())
    }

    fn last_insert_rowid(&self) -> i64 {
        diesel::select(diesel::expression::sql("last_insert_rowid()"))
            .first::<i64>(&self.conn)
            .unwrap()
    }

    pub fn maybe_flush(&mut self) {
        if self.flush_timer.did_fire() {
            self.flush();
        }
    }

    pub fn flush(&mut self) {
        self.conn.commit_transaction().unwrap();
        self.conn.begin_transaction().unwrap();
    }
}

impl Clone for Index {
    fn clone(&self) -> Index {
        Index::new(self.path.clone())
    }
}

impl MsgHandler<Msg, Reply> for Index {
    type Err = MsgError;

    fn handle(&mut self, msg: Msg, reply: Box<Fn(Reply)>) -> Result<(), MsgError> {
        match msg {

            Msg::Insert(entry) => {
                use super::schema::keys::dsl::*;

                let entry = match entry.id {
                    Some(id_) => {
                        // Replace existing entry.
                        diesel::update(keys.find(id_ as i64))
                            .set((parent.eq(entry.parent_id.map(|x| x as i64)),
                                  name.eq(&entry.name[..]),
                                  created.eq(entry.created),
                                  modified.eq(entry.modified),
                                  accessed.eq(entry.accessed)))
                            .execute(&self.conn)
                            .expect("Error updating key");
                        entry
                    }
                    None => {
                        // Insert new entry.
                        {
                            let new = schema::NewKey {
                                parent: entry.parent_id.map(|x| x as i64),
                                name: &entry.name[..],
                                created: entry.created,
                                modified: entry.modified,
                                accessed: entry.accessed,
                                permissions: entry.permissions.map(|x| x as i64),
                                group_id: entry.group_id.map(|x| x as i64),
                                user_id: entry.user_id.map(|x| x as i64),
                                hash: None,
                                persistent_ref: None,
                            };

                            diesel::insert(&new)
                                .into(keys)
                                .execute(&self.conn)
                                .expect("Error inserting key");
                        }
                        let mut entry = entry;
                        entry.id = Some(self.last_insert_rowid() as u64);
                        entry
                    }
                };

                reply(Reply::Entry(entry));
            }

            Msg::Lookup(parent_, name_) => {
                use super::schema::keys::dsl::*;

                let row_opt = match parent_ {
                    Some(p) => {
                        keys.filter(parent.eq(p as i64))
                            .filter(name.eq(&name_[..]))
                            .first::<schema::Key>(&self.conn)
                            .optional()
                            .expect("Error searching keys")
                    }
                    None => {
                        keys.filter(parent.is_null())
                            .filter(name.eq(&name_[..]))
                            .first::<schema::Key>(&self.conn)
                            .optional()
                            .expect("Error searching keys")
                    }
                };

                if let Some(row) = row_opt {
                    reply(Reply::Entry(Entry {
                        id: Some(row.id as u64),
                        parent_id: parent_,
                        name: name_,
                        created: row.created,
                        modified: row.modified,
                        accessed: row.accessed,
                        permissions: row.permissions.map(|x| x as u64),
                        user_id: row.user_id.map(|x| x as u64),
                        group_id: row.group_id.map(|x| x as u64),
                        data_hash: row.hash,
                        data_length: None,
                    }));
                    return Ok(());
                }
                reply(Reply::NotFound);
            }

            Msg::UpdateDataHash(entry, hash_opt, persistent_ref_opt) => {
                use super::schema::keys::dsl::*;

                let id_ = entry.id.expect("Tried to update without an id") as i64;
                assert!(hash_opt.is_some() == persistent_ref_opt.is_some());

                let hash_bytes = hash_opt.map(|h| h.bytes);
                let persistent_ref_bytes = persistent_ref_opt.map(|p| p.as_bytes());

                if entry.modified.is_some() {
                    diesel::update(keys.find(id_)
                                       .filter(modified.eq::<Option<i64>>(None)
                                                       .or(modified.le(entry.modified))))
                        .set((hash.eq(hash_bytes), persistent_ref.eq(persistent_ref_bytes)))
                        .execute(&self.conn)
                        .expect("Error updating key");
                } else {
                    diesel::update(keys.find(id_))
                        .set((hash.eq(hash_bytes), persistent_ref.eq(persistent_ref_bytes)))
                        .execute(&self.conn)
                        .expect("Error updating key");
                }

                self.maybe_flush();
                reply(Reply::UpdateOk);
            }

            Msg::Flush => {
                self.flush();
                reply(Reply::FlushOk);
            }

            Msg::ListDir(parent_opt) => {
                use super::schema::keys::dsl::*;

                let rows = match parent_opt {
                    Some(p) => {
                        keys.filter(parent.eq(p as i64))
                            .load::<schema::Key>(&self.conn)
                            .expect("Error listing keys")
                    }
                    None => {
                        keys.filter(parent.is_null())
                            .load::<schema::Key>(&self.conn)
                            .expect("Error listing keys")
                    }
                };

                reply(Reply::ListResult(rows.into_iter()
                                            .map(|mut r| {
                                                (Entry {
                                                    id: Some(r.id as u64),
                                                    parent_id: r.parent.map(|x| x as u64),
                                                    name: r.name,
                                                    created: r.created,
                                                    modified: r.modified,
                                                    accessed: r.accessed,
                                                    permissions: r.permissions
                                                                  .map(|x| x as u64),
                                                    user_id: r.user_id.map(|x| x as u64),
                                                    group_id: r.group_id.map(|x| x as u64),
                                                    data_hash: r.hash,
                                                    data_length: None,
                                                },
                                                 r.persistent_ref.as_mut().map(|p| {
                                                    blob::ChunkRef::from_bytes(&mut &p[..]).unwrap()
                                                }))
                                            })
                                            .collect()));
            }
        }

        return Ok(());
    }
}
<|endoftext|>


<commit_before>require "../../lib/psql_runner"
require "../../lib/sql_importer"

describe('PsqlRunner', do

  it("should import world database", do |done|
    var thisDir = node.path.dirname(module.filename);
    var worldDbPath = node.path.resolve(thisDir, "../../vendor/datasets/world.sql");

    var importer = new SqlImporter(worldDbPath, {debug: false});

    var onMessageCount = 0;
    var importerOutput = "";

    importer.onMessage(do |message, is_good|
      onMessageCount += 1;
      importerOutput += message;
      if !is_good
        console.log("IMPORT ERROR:" + message);
      end
    end)

    importer.doImport(global.connection, do |success|
      assert(success, true);
      //assert(onMessageCount, 17);

      Fiber(do
        var tables = Model.Table.wrapSync('publicTables')();
        assert(tables.sort(), ['city', 'country', 'countrylanguage'].sort());

        DbCleaner(connection).fibRecreateSchema();
        done();
      end).run()
    end);
  end)

  it("should import booktown database", do |done|
    var thisDir = node.path.dirname(module.filename);
    var worldDbPath = node.path.resolve(thisDir, "../../vendor/datasets/booktown.sql");

    var importer = new SqlImporter(worldDbPath, {debug: false});

    var onMessageCount = 0;
    var importerOutput = "";

    importer.onMessage(do |message, is_good|
      onMessageCount += 1;
      importerOutput += message;
      #if !is_good
      #  console.log("IMPORT ERROR:" + message);
      #end
    end)

    importer.doImport(global.connection, do |success|
      assert(success, true);

      //assert(onMessageCount, 101);

      Fiber(do
        var tables = Model.Table.wrapSync('publicTables')();
        assert(tables.sort(), ['states', 'my_list', 'employees', 'schedules', 'editions',
                              'books', 'publishers', 'shipments', 'stock', 'numeric_values',
                              'daily_inventory', 'money_example', 'customers', 'book_queue',
                              'stock_backup', 'stock_view', 'favorite_books', 'subjects',
                              'distinguished_authors', 'favorite_authors', 'text_sorting',
                              'alternate_stock', 'book_backup', 'recent_shipments', 'authors',
                              ].sort());

        DbCleaner(connection).fibRecreateSchema();
        done();
      end).run()
    end);
  end)

end)
<commit_msg>No need to use sort for arrays in "assert" anymore<commit_after>require "../../lib/psql_runner"
require "../../lib/sql_importer"

describe('PsqlRunner', do

  it("should import world database", do |done|
    var thisDir = node.path.dirname(module.filename);
    var worldDbPath = node.path.resolve(thisDir, "../../vendor/datasets/world.sql");

    var importer = new SqlImporter(worldDbPath, {debug: false});

    var onMessageCount = 0;
    var importerOutput = "";

    importer.onMessage(do |message, is_good|
      onMessageCount += 1;
      importerOutput += message;
      if !is_good
        console.log("IMPORT ERROR:" + message);
      end
    end)

    importer.doImport(global.connection, do |success|
      assert(success, true);
      //assert(onMessageCount, 17);

      Fiber(do
        var tables = Model.Table.wrapSync('publicTables')();
        assert(tables, ['city', 'country', 'countrylanguage']);

        DbCleaner(connection).fibRecreateSchema();
        done();
      end).run()
    end);
  end)

  it("should import booktown database", do |done|
    var thisDir = node.path.dirname(module.filename);
    var worldDbPath = node.path.resolve(thisDir, "../../vendor/datasets/booktown.sql");

    var importer = new SqlImporter(worldDbPath, {debug: false});

    var onMessageCount = 0;
    var importerOutput = "";

    importer.onMessage(do |message, is_good|
      onMessageCount += 1;
      importerOutput += message;
      #if !is_good
      #  console.log("IMPORT ERROR:" + message);
      #end
    end)

    importer.doImport(global.connection, do |success|
      assert(success, true);

      //assert(onMessageCount, 101);

      Fiber(do
        var tables = Model.Table.wrapSync('publicTables')();
        assert(tables, ['states', 'my_list', 'employees', 'schedules', 'editions',
                        'books', 'publishers', 'shipments', 'stock', 'numeric_values',
                        'daily_inventory', 'money_example', 'customers', 'book_queue',
                        'stock_backup', 'stock_view', 'favorite_books', 'subjects',
                        'distinguished_authors', 'favorite_authors', 'text_sorting',
                        'alternate_stock', 'book_backup', 'recent_shipments', 'authors',
                       ]);

        DbCleaner(connection).fibRecreateSchema();
        done();
      end).run()
    end);
  end)

end)
<|endoftext|>


<commit_before>#![crate_name = "uu_hostid"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Maciej Dziardziel <fiedzia@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate libc;

#[macro_use]
extern crate uucore;

use libc::c_long;

static SYNTAX: &str = "[options]";
static SUMMARY: &str = "";
static LONG_HELP: &str = "";

// currently rust libc interface doesn't include gethostid
extern "C" {
    pub fn gethostid() -> c_long;
}

pub fn uumain(args: Vec<String>) -> i32 {
    new_coreopts!(SYNTAX, SUMMARY, LONG_HELP).parse(args);
    hostid();
    0
}

fn hostid() {
    /*
     * POSIX says gethostid returns a "32-bit identifier" but is silent
     * whether it's sign-extended.  Turn off any sign-extension.  This
     * is a no-op unless unsigned int is wider than 32 bits.
     */

    let mut result: c_long;
    unsafe {
        result = gethostid();
    }

    result &= 0xffff_ffff;
    println!("{:0>8x}", result);
}
<commit_msg>fix 32-bit/i686 target builds<commit_after>#![crate_name = "uu_hostid"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Maciej Dziardziel <fiedzia@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate libc;

#[macro_use]
extern crate uucore;

use libc::c_long;

static SYNTAX: &str = "[options]";
static SUMMARY: &str = "";
static LONG_HELP: &str = "";

// currently rust libc interface doesn't include gethostid
extern "C" {
    pub fn gethostid() -> c_long;
}

pub fn uumain(args: Vec<String>) -> i32 {
    new_coreopts!(SYNTAX, SUMMARY, LONG_HELP).parse(args);
    hostid();
    0
}

fn hostid() {
    /*
     * POSIX says gethostid returns a "32-bit identifier" but is silent
     * whether it's sign-extended.  Turn off any sign-extension.  This
     * is a no-op unless unsigned int is wider than 32 bits.
     */

    let mut result: c_long;
    unsafe {
        result = gethostid();
    }

    #[allow(overflowing_literals)]
    let mask = 0xffff_ffff;

    result &= mask;
    println!("{:0>8x}", result);
}
<|endoftext|>