<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// pretty-expanded FIXME #23616

#![allow(dead_code)]

// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.

trait Foo { fn dummy(&self) { } }
impl Foo for isize {}
fn foo(_: [&Foo; 2]) {}
fn foos(_: &[&Foo]) {}
fn foog<T>(_: &[T], _: &[T]) {}

fn bar(_: [Box<Foo>; 2]) {}
fn bars(_: &[Box<Foo>]) {}

fn main() {
    let x: [&Foo; 2] = [&1, &2];
    foo(x);
    foo([&1, &2]);

    let r = &1;
    let x: [&Foo; 2] = [r; 2];
    foo(x);
    foo([&1; 2]);

    let x: &[&Foo] = &[&1, &2];
    foos(x);
    foos(&[&1, &2]);

    let x: &[&Foo] = &[&1, &2];
    let r = &1;
    foog(x, &[r]);

    let x: [Box<Foo>; 2] = [Box::new(1), Box::new(2)];
    bar(x);
    bar([Box::new(1), Box::new(2)]);

    let x: &[Box<Foo>] = &[Box::new(1), Box::new(2)];
    bars(x);
    bars(&[Box::new(1), Box::new(2)]);

    let x: &[Box<Foo>] = &[Box::new(1), Box::new(2)];
    foog(x, &[Box::new(1)]);

    struct T<'a> {
        t: [&'a (Foo+'a); 2]
    }
    let _n = T {
        t: [&1, &2]
    };
    let r = &1;
    let _n = T {
        t: [r; 2]
    };
    let x: [&Foo; 2] = [&1, &2];
    let _n = T {
        t: x
    };

    struct F<'b> {
        t: &'b [&'b (Foo+'b)]
    }
    let _n = F {
        t: &[&1, &2]
    };
    let r = &1;
    let r: [&Foo; 2] = [r; 2];
    let _n = F {
        t: &r
    };
    let x: [&Foo; 2] = [&1, &2];
    let _n = F {
        t: &x
    };

    struct M<'a> {
        t: &'a [Box<Foo+'static>]
    }
    let _n = M {
        t: &[Box::new(1), Box::new(2)]
    };
    let x: [Box<Foo>; 2] = [Box::new(1), Box::new(2)];
    let _n = M {
        t: &x
    };
}
<commit_msg>fallout to run-pass tests.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// pretty-expanded FIXME #23616

#![allow(dead_code)]

// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.

trait Foo { fn dummy(&self) { } }
impl Foo for isize {}
fn foo(_: [&Foo; 2]) {}
fn foos(_: &[&Foo]) {}
fn foog<T>(_: &[T], _: &[T]) {}

fn bar(_: [Box<Foo>; 2]) {}
fn bars(_: &[Box<Foo+'static>]) {}

fn main() {
    let x: [&Foo; 2] = [&1, &2];
    foo(x);
    foo([&1, &2]);

    let r = &1;
    let x: [&Foo; 2] = [r; 2];
    foo(x);
    foo([&1; 2]);

    let x: &[&Foo] = &[&1, &2];
    foos(x);
    foos(&[&1, &2]);

    let x: &[&Foo] = &[&1, &2];
    let r = &1;
    foog(x, &[r]);

    let x: [Box<Foo>; 2] = [Box::new(1), Box::new(2)];
    bar(x);
    bar([Box::new(1), Box::new(2)]);

    let x: &[Box<Foo+'static>] = &[Box::new(1), Box::new(2)];
    bars(x);
    bars(&[Box::new(1), Box::new(2)]);

    let x: &[Box<Foo+'static>] = &[Box::new(1), Box::new(2)];
    foog(x, &[Box::new(1)]);

    struct T<'a> {
        t: [&'a (Foo+'a); 2]
    }
    let _n = T {
        t: [&1, &2]
    };
    let r = &1;
    let _n = T {
        t: [r; 2]
    };
    let x: [&Foo; 2] = [&1, &2];
    let _n = T {
        t: x
    };

    struct F<'b> {
        t: &'b [&'b (Foo+'b)]
    }
    let _n = F {
        t: &[&1, &2]
    };
    let r = &1;
    let r: [&Foo; 2] = [r; 2];
    let _n = F {
        t: &r
    };
    let x: [&Foo; 2] = [&1, &2];
    let _n = F {
        t: &x
    };

    struct M<'a> {
        t: &'a [Box<Foo+'static>]
    }
    let _n = M {
        t: &[Box::new(1), Box::new(2)]
    };
    let x: [Box<Foo>; 2] = [Box::new(1), Box::new(2)];
    let _n = M {
        t: &x
    };
}
<|endoftext|>


<commit_before>// This code is editable and runnable!
fn main() {
    // A simple integer calculator:
    // `+` or `-` means add or subtract by 1
    // `*` or `/` means multiply or divide by 2

    let program = "+ + * - /";
    let mut accumulator = 0;

    for token in program.chars() {
        match token {
            '+' => accumulator += 1,
            '-' => accumulator -= 1,
            '*' => accumulator *= 2,
            '/' => accumulator /= 2,
            _ => { /* ignore everything else */ }
        }
    }

    println!("The program \"{}\" calculates the value {}",
              program, accumulator);
}
<commit_msg>Fix warning about unstable library features<commit_after>#![feature(core)]

// This code is editable and runnable!
fn main() {
    // A simple integer calculator:
    // `+` or `-` means add or subtract by 1
    // `*` or `/` means multiply or divide by 2

    let program = "+ + * - /";
    let mut accumulator = 0;

    for token in program.chars() {
        match token {
            '+' => accumulator += 1,
            '-' => accumulator -= 1,
            '*' => accumulator *= 2,
            '/' => accumulator /= 2,
            _ => { /* ignore everything else */ }
        }
    }

    println!("The program \"{}\" calculates the value {}",
              program, accumulator);
}
<|endoftext|>


<commit_before>//! Tools for testing code that calls the Exit system call.
//!
//! This module is not compatible with Miri because it requires the ability to
//! spawn external processes, which Miri does not support by default. Therefore
//! it is only available for non-Miri tests.

#[cfg(test)]
mod tests;

use std::panic::{catch_unwind, Location, UnwindSafe};

/// Utility for testing code that is expected to call the Exit system call. It
/// is used as follows (inside a unit test case):
///
/// ```
/// use libtock_platform::Syscalls;
/// let _kernel = libtock_unittest::fake::Kernel::new();
/// let exit = libtock_unittest::exit_test("tests::foo", || {
///     libtock_unittest::fake::Syscalls::exit_terminate(0);
/// });
/// assert_eq!(exit, libtock_unittest::ExitCall::Terminate(0));
/// ```
///
/// `exit_test` will panic (to fail the test case) if the code does not call
/// Exit, or if the parameters to exit do not match `expected_exit`.
///
/// `test_name` must match the name of the test case, as is used in Rust's test
/// framework's filter syntax.
///
/// `exit_test` is a hack, and the user should understand how it works to
/// understand its limitations. When the above test case is executed, the
/// following happens:
///
/// 1. The first test process (the one started by the user, e.g. through
///    `cargo test`) executes the `foo()` test case, which calls `exit_test`.
///    We'll call this process A, as it was the first test process to start.
/// 2. `exit_test` spawns a second process, B, by invoking the same test binary
///    as process A. When it does, it passes a filter to process B telling it
///    to only invoke `foo()` (this is the purpose of the `test_name` argument).
///    It also sets an environment variable telling process B that `exit_test`
///    launched it.
/// 3. Process B runs the `foo()` test case, which invokes `exit_test` a second
///    time.
/// 4. `exit_test` in process B uses the environment variable to detect that it
///    is the subprocess version, and it runs closure `fcn`. If `fcn` does not
///    call Exit, it panics. `exit_test` will not return from process B.
/// 5. `exit_test` in process A waits until process B terminates.
/// 6. `exit_test` in process A reads the output of process B to determine
///    whether Exit was called, and if so what arguments were called.
/// 7. `exit_test` in process A returns a value indicating what happened in
///    process B, which `foo()` can make assertions on.
#[track_caller]
pub fn exit_test<F: FnOnce() + UnwindSafe>(test_name: &str, fcn: F) -> ExitCall {
    if let Some(signal_var) = std::env::var_os(SIGNAL_VAR) {
        // We are process B, run the test function.
        run_test(signal_var, fcn)
    } else {
        // We are process A, spawn process B.
        spawn_test(test_name)
    }
}

/// Indicates what type of Exit call was performed, and what completion code was
/// provided.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ExitCall {
    Terminate(u32),
    Restart(u32),
}

// -----------------------------------------------------------------------------
// Public API above, implementation details below.
// -----------------------------------------------------------------------------

// Prints a message telling exit_test the Exit system call was called.
pub(crate) fn signal_exit(exit_call: ExitCall) {
    signal_message(ExitMessage::ExitCall(exit_call));
}

#[doc(hidden)]
impl std::fmt::Display for ExitCall {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        match self {
            ExitCall::Terminate(code) => write!(f, "exit-terminate({})", code),
            ExitCall::Restart(code) => write!(f, "exit-restart({})", code),
        }
    }
}

#[doc(hidden)]
impl std::str::FromStr for ExitCall {
    type Err = ParseExitError;

    fn from_str(s: &str) -> Result<ExitCall, ParseExitError> {
        // Strip off the trailing ), leaving the name and (
        let s = s.strip_suffix(')').ok_or(ParseExitError)?;

        if let Some(s) = s.strip_prefix("exit-terminate(") {
            Ok(ExitCall::Terminate(s.parse().or(Err(ParseExitError))?))
        } else if let Some(s) = s.strip_prefix("exit-restart(") {
            Ok(ExitCall::Restart(s.parse().or(Err(ParseExitError))?))
        } else {
            Err(ParseExitError)
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[doc(hidden)]
pub struct ParseExitError;

// The name of the environment variable used by process A to tell process B that
// it is process B. The value of the environment variable is the location where
// exit_test was called (this location is used to help verify that test_name is
// correct).
const SIGNAL_VAR: &str = "LIBTOCK_UNITTEST_EXIT_TEST";

// This string is printed by process B to tell process A how it exited. It is
// followed by the Display string for a ExitMessage.
const EXIT_STRING: &str = "LIBTOCK_UNITTEST_EXIT_TEST_RESULT: ";

#[derive(Debug, PartialEq)]
enum ExitMessage {
    ExitCall(ExitCall),
    WrongCase,
    DidNotExit,
}

impl std::fmt::Display for ExitMessage {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        match self {
            ExitMessage::ExitCall(exit_call) => write!(f, "ExitCall({})", exit_call),
            ExitMessage::WrongCase => write!(f, "WrongCase"),
            ExitMessage::DidNotExit => write!(f, "DidNotExit"),
        }
    }
}

impl std::str::FromStr for ExitMessage {
    type Err = ParseExitError;

    fn from_str(s: &str) -> Result<ExitMessage, ParseExitError> {
        if let Some(s) = s.strip_prefix("ExitCall(") {
            let s = s.strip_suffix(')').ok_or(ParseExitError)?;
            Ok(ExitMessage::ExitCall(s.parse()?))
        } else if s == "WrongCase" {
            Ok(ExitMessage::WrongCase)
        } else if s == "DidNotExit" {
            Ok(ExitMessage::DidNotExit)
        } else {
            Err(ParseExitError)
        }
    }
}

// Implements process A's behavior for exit_test: spawns this test again as a
// subprocess, only executing the test specified by test_name.
#[track_caller]
fn spawn_test(test_name: &str) -> ExitCall {
    let output = std::process::Command::new(std::env::current_exe().unwrap())
        .args(std::env::args_os())
        .arg("--nocapture")
        .arg("--exact")
        .arg(test_name)
        .envs(std::env::vars_os())
        .env(SIGNAL_VAR, format!("{}", Location::caller()))
        .output()
        .expect("Subprocess exec failed");
    let stdout = String::from_utf8(output.stdout).expect("Subprocess produced invalid UTF-8");
    println!("{} subprocess stdout:\n{}", test_name, stdout);
    let stderr = String::from_utf8(output.stderr).expect("Subprocess produced invalid UTF-8");
    println!("{} subprocess stderr:\n{}", test_name, stderr);

    // Search for the exit message in stdout.
    for line in stdout.lines() {
        if let Some(message) = line.strip_prefix(EXIT_STRING) {
            match message
                .parse::<ExitMessage>()
                .expect("Failed to parse exit message")
            {
                ExitMessage::ExitCall(exit_call) => return exit_call,
                ExitMessage::WrongCase => panic!(
                    "Subprocess executed the wrong test case. Perhaps test_name is incorrect?"
                ),
                ExitMessage::DidNotExit => panic!("Subprocess did not call Exit."),
            }
        }
    }
    panic!("Subprocess did not indicate why it exited. Perhaps test_name is incorrect?");
}

// Used by process B to send a message to process A.
fn signal_message(message: ExitMessage) {
    println!("{}{}", EXIT_STRING, message);
}

// Implements process B's behavior for exit_test. Verifies the test case was
// specified correctly, runs the test function, and prints an error if the test
// function did not call Exit.
#[track_caller]
fn run_test<F: FnOnce() + UnwindSafe>(signal_var: std::ffi::OsString, fcn: F) -> ! {
    let signal_var = signal_var.to_str().expect("Invalid signal variable value");
    if format!("{}", Location::caller()) != signal_var {
        signal_message(ExitMessage::WrongCase);
        std::process::exit(1);
    }
    println!("exit_test: closure return value {:?}", catch_unwind(fcn));
    signal_message(ExitMessage::DidNotExit);
    std::process::exit(1);
}
<commit_msg>`libtock_unittest::exit_test`: give a better error message if `current_exe()` fails.<commit_after>//! Tools for testing code that calls the Exit system call.
//!
//! This module is not compatible with Miri because it requires the ability to
//! spawn external processes, which Miri does not support by default. Therefore
//! it is only available for non-Miri tests.

#[cfg(test)]
mod tests;

use std::panic::{catch_unwind, Location, UnwindSafe};

/// Utility for testing code that is expected to call the Exit system call. It
/// is used as follows (inside a unit test case):
///
/// ```
/// use libtock_platform::Syscalls;
/// let _kernel = libtock_unittest::fake::Kernel::new();
/// let exit = libtock_unittest::exit_test("tests::foo", || {
///     libtock_unittest::fake::Syscalls::exit_terminate(0);
/// });
/// assert_eq!(exit, libtock_unittest::ExitCall::Terminate(0));
/// ```
///
/// `exit_test` will panic (to fail the test case) if the code does not call
/// Exit, or if the parameters to exit do not match `expected_exit`.
///
/// `test_name` must match the name of the test case, as is used in Rust's test
/// framework's filter syntax.
///
/// `exit_test` is a hack, and the user should understand how it works to
/// understand its limitations. When the above test case is executed, the
/// following happens:
///
/// 1. The first test process (the one started by the user, e.g. through
///    `cargo test`) executes the `foo()` test case, which calls `exit_test`.
///    We'll call this process A, as it was the first test process to start.
/// 2. `exit_test` spawns a second process, B, by invoking the same test binary
///    as process A. When it does, it passes a filter to process B telling it
///    to only invoke `foo()` (this is the purpose of the `test_name` argument).
///    It also sets an environment variable telling process B that `exit_test`
///    launched it.
/// 3. Process B runs the `foo()` test case, which invokes `exit_test` a second
///    time.
/// 4. `exit_test` in process B uses the environment variable to detect that it
///    is the subprocess version, and it runs closure `fcn`. If `fcn` does not
///    call Exit, it panics. `exit_test` will not return from process B.
/// 5. `exit_test` in process A waits until process B terminates.
/// 6. `exit_test` in process A reads the output of process B to determine
///    whether Exit was called, and if so what arguments were called.
/// 7. `exit_test` in process A returns a value indicating what happened in
///    process B, which `foo()` can make assertions on.
#[track_caller]
pub fn exit_test<F: FnOnce() + UnwindSafe>(test_name: &str, fcn: F) -> ExitCall {
    if let Some(signal_var) = std::env::var_os(SIGNAL_VAR) {
        // We are process B, run the test function.
        run_test(signal_var, fcn)
    } else {
        // We are process A, spawn process B.
        spawn_test(test_name)
    }
}

/// Indicates what type of Exit call was performed, and what completion code was
/// provided.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ExitCall {
    Terminate(u32),
    Restart(u32),
}

// -----------------------------------------------------------------------------
// Public API above, implementation details below.
// -----------------------------------------------------------------------------

// Prints a message telling exit_test the Exit system call was called.
pub(crate) fn signal_exit(exit_call: ExitCall) {
    signal_message(ExitMessage::ExitCall(exit_call));
}

#[doc(hidden)]
impl std::fmt::Display for ExitCall {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        match self {
            ExitCall::Terminate(code) => write!(f, "exit-terminate({})", code),
            ExitCall::Restart(code) => write!(f, "exit-restart({})", code),
        }
    }
}

#[doc(hidden)]
impl std::str::FromStr for ExitCall {
    type Err = ParseExitError;

    fn from_str(s: &str) -> Result<ExitCall, ParseExitError> {
        // Strip off the trailing ), leaving the name and (
        let s = s.strip_suffix(')').ok_or(ParseExitError)?;

        if let Some(s) = s.strip_prefix("exit-terminate(") {
            Ok(ExitCall::Terminate(s.parse().or(Err(ParseExitError))?))
        } else if let Some(s) = s.strip_prefix("exit-restart(") {
            Ok(ExitCall::Restart(s.parse().or(Err(ParseExitError))?))
        } else {
            Err(ParseExitError)
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[doc(hidden)]
pub struct ParseExitError;

// The name of the environment variable used by process A to tell process B that
// it is process B. The value of the environment variable is the location where
// exit_test was called (this location is used to help verify that test_name is
// correct).
const SIGNAL_VAR: &str = "LIBTOCK_UNITTEST_EXIT_TEST";

// This string is printed by process B to tell process A how it exited. It is
// followed by the Display string for a ExitMessage.
const EXIT_STRING: &str = "LIBTOCK_UNITTEST_EXIT_TEST_RESULT: ";

#[derive(Debug, PartialEq)]
enum ExitMessage {
    ExitCall(ExitCall),
    WrongCase,
    DidNotExit,
}

impl std::fmt::Display for ExitMessage {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        match self {
            ExitMessage::ExitCall(exit_call) => write!(f, "ExitCall({})", exit_call),
            ExitMessage::WrongCase => write!(f, "WrongCase"),
            ExitMessage::DidNotExit => write!(f, "DidNotExit"),
        }
    }
}

impl std::str::FromStr for ExitMessage {
    type Err = ParseExitError;

    fn from_str(s: &str) -> Result<ExitMessage, ParseExitError> {
        if let Some(s) = s.strip_prefix("ExitCall(") {
            let s = s.strip_suffix(')').ok_or(ParseExitError)?;
            Ok(ExitMessage::ExitCall(s.parse()?))
        } else if s == "WrongCase" {
            Ok(ExitMessage::WrongCase)
        } else if s == "DidNotExit" {
            Ok(ExitMessage::DidNotExit)
        } else {
            Err(ParseExitError)
        }
    }
}

// Implements process A's behavior for exit_test: spawns this test again as a
// subprocess, only executing the test specified by test_name.
#[track_caller]
fn spawn_test(test_name: &str) -> ExitCall {
    let current_exe = std::env::current_exe().expect("Unable to find test executable");
    let output = std::process::Command::new(current_exe)
        .args(std::env::args_os())
        .arg("--nocapture")
        .arg("--exact")
        .arg(test_name)
        .envs(std::env::vars_os())
        .env(SIGNAL_VAR, format!("{}", Location::caller()))
        .output()
        .expect("Subprocess exec failed");
    let stdout = String::from_utf8(output.stdout).expect("Subprocess produced invalid UTF-8");
    println!("{} subprocess stdout:\n{}", test_name, stdout);
    let stderr = String::from_utf8(output.stderr).expect("Subprocess produced invalid UTF-8");
    println!("{} subprocess stderr:\n{}", test_name, stderr);

    // Search for the exit message in stdout.
    for line in stdout.lines() {
        if let Some(message) = line.strip_prefix(EXIT_STRING) {
            match message
                .parse::<ExitMessage>()
                .expect("Failed to parse exit message")
            {
                ExitMessage::ExitCall(exit_call) => return exit_call,
                ExitMessage::WrongCase => panic!(
                    "Subprocess executed the wrong test case. Perhaps test_name is incorrect?"
                ),
                ExitMessage::DidNotExit => panic!("Subprocess did not call Exit."),
            }
        }
    }
    panic!("Subprocess did not indicate why it exited. Perhaps test_name is incorrect?");
}

// Used by process B to send a message to process A.
fn signal_message(message: ExitMessage) {
    println!("{}{}", EXIT_STRING, message);
}

// Implements process B's behavior for exit_test. Verifies the test case was
// specified correctly, runs the test function, and prints an error if the test
// function did not call Exit.
#[track_caller]
fn run_test<F: FnOnce() + UnwindSafe>(signal_var: std::ffi::OsString, fcn: F) -> ! {
    let signal_var = signal_var.to_str().expect("Invalid signal variable value");
    if format!("{}", Location::caller()) != signal_var {
        signal_message(ExitMessage::WrongCase);
        std::process::exit(1);
    }
    println!("exit_test: closure return value {:?}", catch_unwind(fcn));
    signal_message(ExitMessage::DidNotExit);
    std::process::exit(1);
}
<|endoftext|>


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

use channel::libra_channel::{self, Receiver};
use futures::{sink::SinkExt, StreamExt};
use libra_canonical_serialization as lcs;
use libra_config::config::RoleType;
use libra_crypto::x25519;
use libra_logger::prelude::*;
use libra_metrics::{register_histogram, DurationHistogram};
use libra_network_address::NetworkAddress;
use libra_types::{
    on_chain_config::{OnChainConfigPayload, ValidatorSet, ON_CHAIN_CONFIG_REGISTRY},
    validator_config::ValidatorConfig,
};
use network::connectivity_manager::{ConnectivityRequest, DiscoverySource};
use once_cell::sync::Lazy;
use std::{collections::HashSet, convert::TryFrom, time::Instant};
use subscription_service::ReconfigSubscription;

pub mod builder;

/// Histogram of idle time of spent in event processing loop
pub static EVENT_PROCESSING_LOOP_IDLE_DURATION_S: Lazy<DurationHistogram> = Lazy::new(|| {
    DurationHistogram::new(
        register_histogram!(
            "simple_onchain_discovery_event_processing_loop_idle_duration_s",
            "Histogram of idle time of spent in event processing loop"
        )
        .unwrap(),
    )
});

/// Histogram of busy time of spent in event processing loop
pub static EVENT_PROCESSING_LOOP_BUSY_DURATION_S: Lazy<DurationHistogram> = Lazy::new(|| {
    DurationHistogram::new(
        register_histogram!(
            "simple_onchain_discovery_event_processing_loop_busy_duration_s",
            "Histogram of busy time of spent in event processing loop"
        )
        .unwrap(),
    )
});

/// Listener which converts published  updates from the OnChainConfig to ConnectivityRequests
/// for the ConnectivityManager.
pub struct ConfigurationChangeListener {
    conn_mgr_reqs_tx: channel::Sender<ConnectivityRequest>,
    reconfig_events: libra_channel::Receiver<(), OnChainConfigPayload>,
    role: RoleType,
}

pub fn gen_simple_discovery_reconfig_subscription(
) -> (ReconfigSubscription, Receiver<(), OnChainConfigPayload>) {
    ReconfigSubscription::subscribe_all(ON_CHAIN_CONFIG_REGISTRY.to_vec(), vec![])
}

/// Extract the network_address from the provided config, depending on role.
fn network_address(role: RoleType, config: &ValidatorConfig) -> Result<NetworkAddress, lcs::Error> {
    match role {
        RoleType::Validator => NetworkAddress::try_from(&config.validator_network_address),
        RoleType::FullNode => NetworkAddress::try_from(&config.full_node_network_address),
    }
}

/// Extracts the public key from the provided config, depending on role.
fn public_key(role: RoleType, config: &ValidatorConfig) -> x25519::PublicKey {
    match role {
        RoleType::Validator => config.validator_network_identity_public_key,
        RoleType::FullNode => config.full_node_network_identity_public_key,
    }
}

/// Extracts a set of ConnectivityRequests from a ValidatorSet which are appropriate for a network with type role.
fn extract_updates(role: RoleType, node_set: ValidatorSet) -> Vec<ConnectivityRequest> {
    let node_list = node_set.payload().to_vec();

    let mut updates = Vec::new();

    // Collect the set of address updates.
    let address_map = node_list
        .iter()
        .flat_map(|node| match network_address(role, node.config()) {
            Ok(addr) => Some((*node.account_address(), vec![addr])),
            Err(e) => {
                warn!("Cannot parse network address {}", e);
                None
            }
        })
        .collect();

    let update_address_req =
        ConnectivityRequest::UpdateAddresses(DiscoverySource::OnChain, address_map);

    updates.push(update_address_req);

    // Collect the set of EligibleNodes
    updates.push(ConnectivityRequest::UpdateEligibleNodes(
        DiscoverySource::OnChain,
        node_list
            .iter()
            .map(|node| {
                let pubkey = public_key(role, node.config());
                let pubkey_set: HashSet<_> = [pubkey].iter().copied().collect();
                (*node.account_address(), pubkey_set)
            })
            .collect(),
    ));

    updates
}

impl ConfigurationChangeListener {
    /// Creates a new ConfigurationListener
    pub fn new(
        conn_mgr_reqs_tx: channel::Sender<ConnectivityRequest>,
        reconfig_events: libra_channel::Receiver<(), OnChainConfigPayload>,
        role: RoleType,
    ) -> Self {
        Self {
            conn_mgr_reqs_tx,
            reconfig_events,
            role,
        }
    }

    /// Processes a received OnChainConfigPayload.  Depending on role (Validator or FullNode), parses
    /// the appropriate configuration changes and passes it to the ConnectionManager channel.
    async fn process_payload(&mut self, payload: OnChainConfigPayload) {
        let node_set: ValidatorSet = payload
            .get()
            .expect("failed to get ValidatorSet from payload");

        let updates = match self.role {
            RoleType::Validator => extract_updates(self.role, node_set),
            RoleType::FullNode => extract_updates(self.role, node_set),
        };

        info!(
            "Update {} Network about new Node IDs",
            self.role.to_string()
        );

        for update in updates {
            match self.conn_mgr_reqs_tx.send(update).await {
                Ok(()) => (),
                Err(e) => warn!("Failed to send update to ConnectivityManager {}", e),
            }
        }
    }

    /// Starts the listener to wait on reconfiguration events.  Creates an infinite loop.
    pub async fn start(mut self) {
        loop {
            let start_idle_time = Instant::now();
            let payload = self.reconfig_events.select_next_some().await;
            let idle_duration = start_idle_time.elapsed();
            let start_process_time = Instant::now();
            self.process_payload(payload).await;
            let process_duration = start_process_time.elapsed();

            EVENT_PROCESSING_LOOP_IDLE_DURATION_S.observe_duration(idle_duration);
            EVENT_PROCESSING_LOOP_BUSY_DURATION_S.observe_duration(process_duration);
        }
    }
}
<commit_msg>[network] simple onchain discovery derive pubkeys from addrs<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use channel::libra_channel::{self, Receiver};
use futures::{sink::SinkExt, StreamExt};
use libra_canonical_serialization as lcs;
use libra_config::config::RoleType;
use libra_crypto::x25519;
use libra_logger::prelude::*;
use libra_metrics::{register_histogram, DurationHistogram};
use libra_network_address::NetworkAddress;
use libra_types::{
    on_chain_config::{OnChainConfigPayload, ValidatorSet, ON_CHAIN_CONFIG_REGISTRY},
    validator_config::ValidatorConfig,
};
use network::connectivity_manager::{ConnectivityRequest, DiscoverySource};
use once_cell::sync::Lazy;
use std::{collections::HashSet, convert::TryFrom, iter, time::Instant};
use subscription_service::ReconfigSubscription;

pub mod builder;

/// Histogram of idle time of spent in event processing loop
pub static EVENT_PROCESSING_LOOP_IDLE_DURATION_S: Lazy<DurationHistogram> = Lazy::new(|| {
    DurationHistogram::new(
        register_histogram!(
            "simple_onchain_discovery_event_processing_loop_idle_duration_s",
            "Histogram of idle time of spent in event processing loop"
        )
        .unwrap(),
    )
});

/// Histogram of busy time of spent in event processing loop
pub static EVENT_PROCESSING_LOOP_BUSY_DURATION_S: Lazy<DurationHistogram> = Lazy::new(|| {
    DurationHistogram::new(
        register_histogram!(
            "simple_onchain_discovery_event_processing_loop_busy_duration_s",
            "Histogram of busy time of spent in event processing loop"
        )
        .unwrap(),
    )
});

/// Listener which converts published  updates from the OnChainConfig to ConnectivityRequests
/// for the ConnectivityManager.
pub struct ConfigurationChangeListener {
    conn_mgr_reqs_tx: channel::Sender<ConnectivityRequest>,
    reconfig_events: libra_channel::Receiver<(), OnChainConfigPayload>,
    role: RoleType,
}

pub fn gen_simple_discovery_reconfig_subscription(
) -> (ReconfigSubscription, Receiver<(), OnChainConfigPayload>) {
    ReconfigSubscription::subscribe_all(ON_CHAIN_CONFIG_REGISTRY.to_vec(), vec![])
}

/// Extract the network_address from the provided config, depending on role.
fn network_address(role: RoleType, config: &ValidatorConfig) -> Result<NetworkAddress, lcs::Error> {
    match role {
        RoleType::Validator => NetworkAddress::try_from(&config.validator_network_address),
        RoleType::FullNode => NetworkAddress::try_from(&config.full_node_network_address),
    }
}

/// Extracts the public key from the provided config, depending on role.
fn public_key(role: RoleType, config: &ValidatorConfig) -> x25519::PublicKey {
    match role {
        RoleType::Validator => config.validator_network_identity_public_key,
        RoleType::FullNode => config.full_node_network_identity_public_key,
    }
}

/// Extracts a set of ConnectivityRequests from a ValidatorSet which are appropriate for a network with type role.
fn extract_updates(role: RoleType, node_set: ValidatorSet) -> Vec<ConnectivityRequest> {
    let node_list = node_set.payload().to_vec();

    let mut updates = Vec::new();

    // Collect the set of address updates.
    let address_map = node_list
        .iter()
        .filter_map(|node| match network_address(role, node.config()) {
            Ok(addr) => Some((*node.account_address(), vec![addr])),
            Err(err) => {
                let account = node.account_address();
                let config = node.config();
                warn!(
                    "Failed to parse network address for account: {}, role: {}, config: {:?}, err: {:?}",
                    account, role, config, err
                );
                None
            }
        })
        .collect();

    let update_address_req =
        ConnectivityRequest::UpdateAddresses(DiscoverySource::OnChain, address_map);

    updates.push(update_address_req);

    // Collect the set of EligibleNodes
    updates.push(ConnectivityRequest::UpdateEligibleNodes(
        DiscoverySource::OnChain,
        node_list
            .iter()
            .map(|node| {
                // TODO(philiphayes): remove this after removing pubkey field
                let pubkey = public_key(role, node.config());
                // parse out pubkey from address
                let pubkey_set: HashSet<_> = network_address(role, node.config())
                    .ok()
                    .iter()
                    .filter_map(NetworkAddress::find_noise_proto)
                    // for now, also add the explicit pubkey field
                    .chain(iter::once(pubkey))
                    .collect();
                (*node.account_address(), pubkey_set)
            })
            .collect(),
    ));

    updates
}

impl ConfigurationChangeListener {
    /// Creates a new ConfigurationListener
    pub fn new(
        conn_mgr_reqs_tx: channel::Sender<ConnectivityRequest>,
        reconfig_events: libra_channel::Receiver<(), OnChainConfigPayload>,
        role: RoleType,
    ) -> Self {
        Self {
            conn_mgr_reqs_tx,
            reconfig_events,
            role,
        }
    }

    /// Processes a received OnChainConfigPayload.  Depending on role (Validator or FullNode), parses
    /// the appropriate configuration changes and passes it to the ConnectionManager channel.
    async fn process_payload(&mut self, payload: OnChainConfigPayload) {
        let node_set: ValidatorSet = payload
            .get()
            .expect("failed to get ValidatorSet from payload");

        let updates = match self.role {
            RoleType::Validator => extract_updates(self.role, node_set),
            RoleType::FullNode => extract_updates(self.role, node_set),
        };

        info!(
            "Update {} Network about new Node IDs",
            self.role.to_string()
        );

        for update in updates {
            match self.conn_mgr_reqs_tx.send(update).await {
                Ok(()) => (),
                Err(e) => warn!("Failed to send update to ConnectivityManager {}", e),
            }
        }
    }

    /// Starts the listener to wait on reconfiguration events.  Creates an infinite loop.
    pub async fn start(mut self) {
        loop {
            let start_idle_time = Instant::now();
            let payload = self.reconfig_events.select_next_some().await;
            let idle_duration = start_idle_time.elapsed();
            let start_process_time = Instant::now();
            self.process_payload(payload).await;
            let process_duration = start_process_time.elapsed();

            EVENT_PROCESSING_LOOP_IDLE_DURATION_S.observe_duration(idle_duration);
            EVENT_PROCESSING_LOOP_BUSY_DURATION_S.observe_duration(process_duration);
        }
    }
}
<|endoftext|>


<commit_before>//! A Web Socket server

#[crate_id = "rust-ws"];

extern mod extra;
extern mod http;
extern mod rust_crypto = "rust-crypto";

use rust_crypto::sha1::Sha1;
use rust_crypto::digest::Digest;
use extra::base64::{ToBase64, STANDARD};

use std::io::net::ip::{SocketAddr, Ipv4Addr};
use std::io::Writer;
use extra::time;

use http::server::{Config, Server, Request, ResponseWriter};
use http::status::SwitchingProtocols;
use http::headers::HeaderEnum;
use http::headers::response::ExtensionHeader;
use http::headers::content_type::MediaType;
use http::headers::connection::Token;
use http::method::Get;

static WEBSOCKET_SALT: &'static str = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

#[deriving(Clone)]
struct WebSocketServer;

trait HandleHTTP {
    fn handle_http_request(&self, r: &Request, w: &mut ResponseWriter);
}

impl HandleHTTP for WebSocketServer {
    fn handle_http_request(&self, r: &Request, w: &mut ResponseWriter) {
        w.headers.date = Some(time::now_utc());
        w.headers.server = Some(~"rust-ws/0.0-pre");
        w.headers.content_type = Some(MediaType {
            type_: ~"text",
            subtype: ~"html",
            parameters: ~[(~"charset", ~"UTF-8")]
        });
        w.write(bytes!("<!DOCTYPE html><title>Rust Web Socket Server</title>
Rust Web Socket Server
"));
    }
}

impl Server for WebSocketServer {
    fn get_config(&self) -> Config {
        Config { bind_address: SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 8001 } }
    }

    fn handle_request(&self, r: &Request, w: &mut ResponseWriter) {
        // TODO allow configuration of endpoint for websocket
        match (&r.method, &r.headers.upgrade){
          // (&Get, &Some(~"websocket"), &Some(~[Token(~"Upgrade")])) => { // FIXME this doesn't work. but client must have the header "Connection: Upgrade"
          (&Get, &Some(~"websocket")) => { // TODO client must have the header "Connection: Upgrade"
            w.status = SwitchingProtocols;
            w.headers.upgrade = Some(~"websocket");

            // w.headers.transfer_encoding = None;
            w.headers.content_length = Some(0);

            w.headers.connection = Some(~[Token(~"Upgrade")]);

            // FIXME must we iter?
            for header in r.headers.iter() {
              match (header.header_name(), header.header_value()) {
                (~"Sec-Websocket-Key", val) => {
                  //  NOTE from RFC 6455
                  //  As an example, if the value of the |Sec-WebSocket-Key|
                  //  header field in the client's handshake were
                  //  "dGhlIHNhbXBsZSBub25jZQ==", the server would append the
                  //  string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" to form the
                  //  string "dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-
                  //  C5AB0DC85B11".  The server would then take the SHA-1 hash
                  //  of this string, giving the value 0xb3 0x7a 0x4f 0x2c 0xc0
                  //  0x62 0x4f 0x16 0x90 0xf6 0x46 0x06 0xcf 0x38 0x59 0x45
                  //  0xb2 0xbe 0xc4 0xea.  This value is then base64-encoded,
                  //  to give the value "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", which
                  //  would be returned in the |Sec-WebSocket-Accept| header
                  //  field.

                  let mut sh = Sha1::new();
                  let mut out = [0u8, ..20];
                  sh.input_str(val + WEBSOCKET_SALT);
                  sh.result(out);
                  let sec_websocket_accept = out.to_base64(STANDARD);
                  debug!("sec websocket accept: {}", sec_websocket_accept);
                  w.headers.insert(ExtensionHeader(~"Sec-WebSocket-Accept", sec_websocket_accept));

                  w.headers.date = Some(time::now_utc());
                  w.headers.server = Some(~"rust-ws/0.0-pre");
                }
                (name, val) => {
                  debug!("{}: {}", name, val);
                }
              }
            }
          },
          (&_, &Some(_)) => {}, // handle other upgrade - this is rare apparently, but may be used for TLS for example. not sure if browsers actually implement it though.
          (&_, &None) => self.handle_http_request(r, w)
        }
    }
}

fn main() {
    WebSocketServer.serve_forever();
}
<commit_msg>fix indentation and other minor fixes<commit_after>//! A Web Socket Server

#[crate_id = "rust-ws"];

extern mod extra;
extern mod http;
extern mod rust_crypto = "rust-crypto";

use rust_crypto::sha1::Sha1;
use rust_crypto::digest::Digest;
use extra::base64::{ToBase64, STANDARD};

use std::io::net::ip::{SocketAddr, Ipv4Addr};
use std::io::Writer;
use extra::time;

use http::server::{Config, Server, Request, ResponseWriter};
use http::status::SwitchingProtocols;
use http::headers::HeaderEnum;
use http::headers::response::ExtensionHeader;
use http::headers::content_type::MediaType;
use http::headers::connection::Token;
use http::method::Get;

static WEBSOCKET_SALT: &'static str = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

#[deriving(Clone)]
struct WebSocketServer;

trait HandleHTTP {
    fn handle_http_request(&self, r: &Request, w: &mut ResponseWriter);
}

impl HandleHTTP for WebSocketServer {
    fn handle_http_request(&self, r: &Request, w: &mut ResponseWriter) {
        w.headers.date = Some(time::now_utc());
        w.headers.server = Some(~"rust-ws/0.0-pre");
        w.headers.content_type = Some(MediaType {
            type_: ~"text",
            subtype: ~"html",
            parameters: ~[(~"charset", ~"UTF-8")]
        });
        w.write(bytes!("<!DOCTYPE html><title>Rust Web Socket Server</title>
Rust Web Socket Server
"));
    }
}

impl Server for WebSocketServer {
    fn get_config(&self) -> Config {
        Config { bind_address: SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 8001 } }
    }

    fn handle_request(&self, r: &Request, w: &mut ResponseWriter) {
        // TODO allow configuration of endpoint for websocket
        match (&r.method, &r.headers.upgrade){
            // (&Get, &Some(~"websocket"), &Some(~[Token(~"Upgrade")])) => { // FIXME this doesn't work. but client must have the header "Connection: Upgrade"
            (&Get, &Some(~"websocket")) => { // TODO client must have the header "Connection: Upgrade"
                w.status = SwitchingProtocols;
                w.headers.upgrade = Some(~"websocket");

                // w.headers.transfer_encoding = None;
                w.headers.content_length = Some(0);

                w.headers.connection = Some(~[Token(~"Upgrade")]);

                // FIXME must we iter?
                for header in r.headers.iter() {
                    match (header.header_name(), header.header_value()) {
                        (~"Sec-Websocket-Key", val) => {
                            //  NOTE from RFC 6455
                            //  As an example, if the value of the |Sec-WebSocket-Key|
                            //  header field in the client's handshake were
                            //  "dGhlIHNhbXBsZSBub25jZQ==", the server would append the
                            //  string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" to form the
                            //  string "dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-
                            //  C5AB0DC85B11".  The server would then take the SHA-1 hash
                            //  of this string, giving the value 0xb3 0x7a 0x4f 0x2c 0xc0
                            //  0x62 0x4f 0x16 0x90 0xf6 0x46 0x06 0xcf 0x38 0x59 0x45
                            //  0xb2 0xbe 0xc4 0xea.  This value is then base64-encoded,
                            //  to give the value "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", which
                            //  would be returned in the |Sec-WebSocket-Accept| header
                            //  field.

                            let mut sh = Sha1::new();
                            let mut out = [0u8, ..20];
                            sh.input_str(val + WEBSOCKET_SALT);
                            sh.result(out);
                            let sec_websocket_accept = out.to_base64(STANDARD);
                            debug!("sec websocket accept: {}", sec_websocket_accept);
                            w.headers.insert(ExtensionHeader(~"Sec-WebSocket-Accept", sec_websocket_accept));

                            w.headers.date = Some(time::now_utc());
                            w.headers.server = Some(~"rust-ws/0.0-pre");
                        }
                        (name, val) => {
                            debug!("{}: {}", name, val);
                        }
                    }
                }
            },
            (&_, &_) => self.handle_http_request(r, w)
        }
    }
}

fn main() {
    WebSocketServer.serve_forever();
}
<|endoftext|>


<commit_before> #![feature(buf_stream)]

#[macro_use]
extern crate log;
extern crate url;
extern crate capnp;

pub mod yak_capnp;

use std::net::TcpStream;
use std::io::{self,BufStream,Write};
use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, MallocMessageBuilder, ReaderOptions};

use url::{Url,SchemeType,UrlParser};

use yak_capnp::{client_request,client_response};

fn yak_url_scheme(_scheme: &str) -> SchemeType {
  SchemeType::Relative(0)
}

pub struct Client {
  connection: BufStream<TcpStream>,
  space: String,
}

#[derive(Debug)]
pub enum YakError {
  UrlParseError(url::ParseError),
  InvalidUrl(Url),
  IoError(io::Error),
  CapnpError(capnp::Error),
  CapnpNotInSchema(capnp::NotInSchema),
  ProtocolError
}

#[derive(PartialEq,Eq,PartialOrd,Ord,Debug, Clone)]
pub struct Datum {
  pub content: Vec<u8>
}

pub struct Request {
  space: String,
  operation: Operation,
}
pub enum Operation {
  Truncate ,
  Read { key: Vec<u8> },
  Write { key: Vec<u8>, value: Vec<u8> },
}

impl Request {
  fn encode<B: MessageBuilder>(&self, message: &mut B) {
    match &self.operation {
      &Operation::Truncate => Self::encode_truncate(message, &self.space),
      &Operation::Read { key: ref key } => Self::encode_read(message, &self.space, &key),
      &Operation::Write { key: ref key, value: ref val } => Self::encode_write(message, &self.space, &key, &val),
    }
  }

  fn truncate(space: &str) -> Request {
    Request { space: space.to_string(), operation: Operation::Truncate }
  }

  fn read(space: &str, key: &[u8]) -> Request {
    Request { space: space.to_string(), operation: Operation::Read { key: key.to_vec() } }
  }

  fn write(space: &str, key: &[u8], value: &[u8]) -> Request {
    Request { space: space.to_string(), operation: Operation::Write { key: key.to_owned(), value: value.to_owned() } }
  }

  fn encode_truncate<B: MessageBuilder>(message: &mut B, space: &str) {
    let mut rec = message.init_root::<client_request::Builder>();
    let mut trunc = rec.init_truncate();
    trunc.set_space(space)
  }

  fn encode_write<B: MessageBuilder>(message: &mut B, space: &str, key: &[u8], val: &[u8]) {
    let mut rec = message.init_root::<client_request::Builder>();
    let mut req = rec.init_write();
    req.set_space(space);
    req.set_key(key);
    req.set_value(val);
  }

  fn encode_read<B: MessageBuilder>(message: &mut B, space: &str, key: &[u8]) {
      let mut rec = message.init_root::<client_request::Builder>();
      let mut req = rec.init_read();
      req.set_space(space);
      req.set_key(key)
  }
}

pub enum Response {
  Okay,
  OkayData(Vec<Datum>)
}

impl Response {
  fn decode<R: MessageReader>(message: &R) -> Result<Response, YakError> {
    let msg = try!(message.get_root::<client_response::Reader>());
    match try!(msg.which()) {
      client_response::Ok(()) => Ok(Response::Okay),
      client_response::OkData(d) => {
        debug!("Got response Data: ");
        let mut data = Vec::with_capacity(try!(d).len() as usize);
        for it in try!(d).iter() {
          let val : Vec<u8> = try!(it.get_value()).iter().map(|v|v.clone()).collect();
          data.push(Datum { content: val });
        }
        Ok(Response::OkayData(data))
      }
    }
  }

  pub fn expect_ok(&self) -> Result<(), YakError> {
    match self {
      &Response::Okay => Ok(()),
      &Response::OkayData(_) => Err(YakError::ProtocolError)
    }
  }

  pub fn expect_datum_list(&self) -> Result<Vec<Datum>, YakError> {
    match self {
      &Response::OkayData(ref result) => Ok(result.clone()),
      &Response::Okay => Err(YakError::ProtocolError)
    }
  }
}

impl Client {
  pub fn connect(loc: &str) -> Result<Client, YakError> {
    let mut p = UrlParser::new();
    p.scheme_type_mapper(yak_url_scheme);
    let url = try!(p.parse(loc));
    debug!("yak:url: {:?}", url);
    let (addr, space) = match (url.domain(), url.port(), url.serialize_path()) {
      (Some(host), Some(port), Some(path)) => ((host, port), path),
      _ => return Err(YakError::InvalidUrl(url.clone()))
    };

    let sock = try!(TcpStream::connect(addr));
    debug!("connected:{:?}", sock);
    Ok(Client { connection: BufStream::new(sock), space: space })
  }

  fn expect_ok<R: MessageReader>(message: &R) -> Result<(), YakError> {
    let msg = try!(message.get_root::<client_response::Reader>());
    debug!("Got response");
    match try!(msg.which()) {
      client_response::Ok(()) => Ok(()),
      other => Err(YakError::ProtocolError)
    }
  }

  fn expect_datum_list<R: MessageReader>(message_reader: &R) -> Result<Vec<Datum>, YakError> {
    let msg = try!(message_reader.get_root::<client_response::Reader>());
    match try!(msg.which()) {
      client_response::OkData(d) => {
        debug!("Got response Data: ");
        let mut data = Vec::with_capacity(try!(d).len() as usize);
        for it in try!(d).iter() {
          let val : Vec<u8> = try!(it.get_value()).iter().map(|v|v.clone()).collect();
          data.push(Datum { content: val });
        }

        Ok(data)
      },
      other => Err(YakError::ProtocolError)
    }
  }

  fn send(&mut self, req: Request) -> Result<(), YakError> {
    let mut message = MallocMessageBuilder::new_default();
    req.encode(&mut message);
    try!(serialize_packed::write_message(&mut self.connection, &mut message));
    try!(self.connection.flush());
    Ok(())
  }

  fn read_response(&mut self) -> Result<Response,YakError> {
    let message_reader =
      try!(serialize_packed::read_message(
	&mut self.connection, ReaderOptions::new()));
    let resp = try!(Response::decode(&message_reader));
    Ok(resp)
  }

  pub fn truncate(&mut self) -> Result<(), YakError> {
    let req = Request::truncate(&self.space);
    try!(self.send(req));
    debug!("Waiting for response");
    try!(self.read_response()).expect_ok()
  }

  pub fn write(&mut self, key: &[u8], val: &[u8]) -> Result<(), YakError> {
    let req = Request::write(&self.space, key, val);
    try!(self.send(req));
    debug!("Waiting for response");
    try!(self.read_response()).expect_ok()
  }

  pub fn read(&mut self, key: &[u8]) -> Result<Vec<Datum>, YakError> {
    let req = Request::read(&self.space, key);
    try!(self.send(req));
    debug!("Waiting for response");

    try!(self.read_response()).expect_datum_list()
  }
}

impl From<url::ParseError> for YakError {
  fn from(err: url::ParseError) -> YakError {
    YakError::UrlParseError(err)
  }
}

impl From<io::Error> for YakError {
  fn from(err: io::Error) -> YakError {
    YakError::IoError(err)
  }
}

impl From<capnp::Error> for YakError {
  fn from(err: capnp::Error) -> YakError {
    YakError::CapnpError(err)
  }
}

impl From<capnp::NotInSchema> for YakError {
  fn from(err: capnp::NotInSchema) -> YakError {
    YakError::CapnpNotInSchema(err)
  }
}
<commit_msg>Extract wire protocol wrapper type.<commit_after> #![feature(buf_stream)]

#[macro_use]
extern crate log;
extern crate url;
extern crate capnp;

pub mod yak_capnp;

use std::net::{TcpStream,ToSocketAddrs};
use std::io::{self,BufStream,Write};
use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, MallocMessageBuilder, ReaderOptions};

use url::{Url,SchemeType,UrlParser};

use yak_capnp::{client_request,client_response};

fn yak_url_scheme(_scheme: &str) -> SchemeType {
  SchemeType::Relative(0)
}

#[derive(Debug)]
pub enum YakError {
  UrlParseError(url::ParseError),
  InvalidUrl(Url),
  IoError(io::Error),
  CapnpError(capnp::Error),
  CapnpNotInSchema(capnp::NotInSchema),
  ProtocolError
}

#[derive(PartialEq,Eq,PartialOrd,Ord,Debug, Clone)]
pub struct Datum {
  pub content: Vec<u8>
}

pub struct Request {
  space: String,
  operation: Operation,
}
pub enum Operation {
  Truncate ,
  Read { key: Vec<u8> },
  Write { key: Vec<u8>, value: Vec<u8> },
}

impl Request {
  fn truncate(space: &str) -> Request {
    Request { space: space.to_string(), operation: Operation::Truncate }
  }

  fn read(space: &str, key: &[u8]) -> Request {
    Request { space: space.to_string(), operation: Operation::Read { key: key.to_vec() } }
  }

  fn write(space: &str, key: &[u8], value: &[u8]) -> Request {
    Request { space: space.to_string(), operation: Operation::Write { key: key.to_owned(), value: value.to_owned() } }
  }

  fn encode_truncate<B: MessageBuilder>(message: &mut B, space: &str) {
    let mut rec = message.init_root::<client_request::Builder>();
    let mut trunc = rec.init_truncate();
    trunc.set_space(space)
  }

  fn encode_write<B: MessageBuilder>(message: &mut B, space: &str, key: &[u8], val: &[u8]) {
    let mut rec = message.init_root::<client_request::Builder>();
    let mut req = rec.init_write();
    req.set_space(space);
    req.set_key(key);
    req.set_value(val);
  }

  fn encode_read<B: MessageBuilder>(message: &mut B, space: &str, key: &[u8]) {
      let mut rec = message.init_root::<client_request::Builder>();
      let mut req = rec.init_read();
      req.set_space(space);
      req.set_key(key)
  }
}

impl WireMessage for Request {
  fn encode<B: MessageBuilder>(&self, message: &mut B) {
    match &self.operation {
      &Operation::Truncate => Self::encode_truncate(message, &self.space),
      &Operation::Read { key: ref key } => Self::encode_read(message, &self.space, &key),
      &Operation::Write { key: ref key, value: ref val } => Self::encode_write(message, &self.space, &key, &val),
    }
  }

  fn decode<R: MessageReader>(message: &R) -> Result<Self, YakError> {
    unimplemented!()
  }
}

pub enum Response {
  Okay,
  OkayData(Vec<Datum>)
}

impl Response {
  pub fn expect_ok(&self) -> Result<(), YakError> {
    match self {
      &Response::Okay => Ok(()),
      &Response::OkayData(_) => Err(YakError::ProtocolError)
    }
  }

  pub fn expect_datum_list(&self) -> Result<Vec<Datum>, YakError> {
    match self {
      &Response::OkayData(ref result) => Ok(result.clone()),
      &Response::Okay => Err(YakError::ProtocolError)
    }
  }
}

impl WireMessage for Response {
  fn encode<B: MessageBuilder>(&self, message: &mut B) {
    unimplemented!()
  }

  fn decode<R: MessageReader>(message: &R) -> Result<Self, YakError> {
    let msg = try!(message.get_root::<client_response::Reader>());
    match try!(msg.which()) {
      client_response::Ok(()) => Ok(Response::Okay),
      client_response::OkData(d) => {
        debug!("Got response Data: ");
        let mut data = Vec::with_capacity(try!(d).len() as usize);
        for it in try!(d).iter() {
          let val : Vec<u8> = try!(it.get_value()).iter().map(|v|v.clone()).collect();
          data.push(Datum { content: val });
        }
        Ok(Response::OkayData(data))
      }
    }
  }
}
#[derive(Debug)]
struct WireProtocol<S: io::Read+io::Write> {
  connection: BufStream<S>,
}

trait WireMessage {
  fn encode<B: MessageBuilder>(&self, message: &mut B);
  fn decode<R: MessageReader>(message: &R) -> Result<Self, YakError>;
}

impl WireProtocol<TcpStream> {
  fn connect<A: ToSocketAddrs>(addr: A) -> Result<Self, YakError> {
    let sock = try!(TcpStream::connect(addr));
    debug!("connected:{:?}", sock);
    let stream = BufStream::new(sock);
    Ok(WireProtocol { connection: stream })
  }

  fn send<M : WireMessage>(&mut self, req: M) -> Result<(), YakError> {
    let mut message = MallocMessageBuilder::new_default();
    req.encode(&mut message);
    try!(serialize_packed::write_message(&mut self.connection, &mut message));
    try!(self.connection.flush());
    Ok(())
  }

  fn read<M : WireMessage>(&mut self) -> Result<M,YakError> {
    let message_reader =
      try!(serialize_packed::read_message(
	&mut self.connection, ReaderOptions::new()));
    let resp = try!(M::decode(&message_reader));
    Ok(resp)
  }
}

#[derive(Debug)]
pub struct Client {
  protocol: WireProtocol<TcpStream>,
  space: String,
}

impl Client {
  pub fn connect(loc: &str) -> Result<Client, YakError> {
    let mut p = UrlParser::new();
    p.scheme_type_mapper(yak_url_scheme);
    let url = try!(p.parse(loc));
    debug!("yak:url: {:?}", url);
    let (addr, space) = match (url.domain(), url.port(), url.serialize_path()) {
      (Some(host), Some(port), Some(path)) => ((host, port), path),
      _ => return Err(YakError::InvalidUrl(url.clone()))
    };

    let proto = try!(WireProtocol::connect(addr));
    Ok(Client { protocol: proto, space: space })
  }

  fn expect_ok<R: MessageReader>(message: &R) -> Result<(), YakError> {
    let msg = try!(message.get_root::<client_response::Reader>());
    debug!("Got response");
    match try!(msg.which()) {
      client_response::Ok(()) => Ok(()),
      other => Err(YakError::ProtocolError)
    }
  }

  fn expect_datum_list<R: MessageReader>(message_reader: &R) -> Result<Vec<Datum>, YakError> {
    let msg = try!(message_reader.get_root::<client_response::Reader>());
    match try!(msg.which()) {
      client_response::OkData(d) => {
        debug!("Got response Data: ");
        let mut data = Vec::with_capacity(try!(d).len() as usize);
        for it in try!(d).iter() {
          let val : Vec<u8> = try!(it.get_value()).iter().map(|v|v.clone()).collect();
          data.push(Datum { content: val });
        }

        Ok(data)
      },
      other => Err(YakError::ProtocolError)
    }
  }

  pub fn truncate(&mut self) -> Result<(), YakError> {
    let req = Request::truncate(&self.space);
    try!(self.protocol.send(req));
    debug!("Waiting for response");
    try!(self.protocol.read::<Response>()).expect_ok()
  }

  pub fn write(&mut self, key: &[u8], val: &[u8]) -> Result<(), YakError> {
    let req = Request::write(&self.space, key, val);
    try!(self.protocol.send(req));
    debug!("Waiting for response");
    try!(self.protocol.read::<Response>()).expect_ok()
  }

  pub fn read(&mut self, key: &[u8]) -> Result<Vec<Datum>, YakError> {
    let req = Request::read(&self.space, key);
    try!(self.protocol.send(req));
    debug!("Waiting for response");

    try!(self.protocol.read::<Response>()).expect_datum_list()
  }
}

impl From<url::ParseError> for YakError {
  fn from(err: url::ParseError) -> YakError {
    YakError::UrlParseError(err)
  }
}

impl From<io::Error> for YakError {
  fn from(err: io::Error) -> YakError {
    YakError::IoError(err)
  }
}

impl From<capnp::Error> for YakError {
  fn from(err: capnp::Error) -> YakError {
    YakError::CapnpError(err)
  }
}

impl From<capnp::NotInSchema> for YakError {
  fn from(err: capnp::NotInSchema) -> YakError {
    YakError::CapnpNotInSchema(err)
  }
}
<|endoftext|>


<commit_before>//! The `filter` element.

use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::allowed_url::Fragment;
use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, Element, ElementResult, SetAttributes};
use crate::error::ValueErrorKind;
use crate::iri::IRI;
use crate::length::*;
use crate::node::{Node, NodeBorrow};
use crate::parsers::{Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_bag::PropertyBag;
use crate::rect::Rect;
use crate::transform::Transform;

/// The <filter> node.
pub struct Filter {
    x: Length<Horizontal>,
    y: Length<Vertical>,
    width: Length<Horizontal>,
    height: Length<Vertical>,
    filterunits: CoordUnits,
    primitiveunits: CoordUnits,
}

impl Default for Filter {
    /// Constructs a new `Filter` with default properties.
    fn default() -> Self {
        Self {
            x: Length::<Horizontal>::parse_str("-10%").unwrap(),
            y: Length::<Vertical>::parse_str("-10%").unwrap(),
            width: Length::<Horizontal>::parse_str("120%").unwrap(),
            height: Length::<Vertical>::parse_str("120%").unwrap(),
            filterunits: CoordUnits::ObjectBoundingBox,
            primitiveunits: CoordUnits::UserSpaceOnUse,
        }
    }
}

impl Filter {
    pub fn get_filter_units(&self) -> CoordUnits {
        self.filterunits
    }

    pub fn get_primitive_units(&self) -> CoordUnits {
        self.primitiveunits
    }

    /// Computes and returns the filter effects region.
    pub fn compute_effects_region(
        &self,
        computed_from_target_node: &ComputedValues,
        draw_ctx: &mut DrawingCtx,
        transform: Transform,
        width: f64,
        height: f64,
    ) -> BoundingBox {
        // Filters use the properties of the target node.
        let values = computed_from_target_node;

        let mut bbox = BoundingBox::new();

        // transform is set up in FilterContext::new() in such a way that for
        // filterunits == ObjectBoundingBox it includes scaling to correct width, height and
        // this is why width and height are set to 1, 1 (and for filterunits ==
        // UserSpaceOnUse, transform doesn't include scaling because in this case the correct
        // width, height already happens to be the viewbox width, height).
        //
        // It's done this way because with ObjectBoundingBox, non-percentage values are supposed to
        // represent the fractions of the referenced node, and with width and height = 1, 1 this
        // works out exactly like that.
        let params = if self.filterunits == CoordUnits::ObjectBoundingBox {
            draw_ctx.push_view_box(1.0, 1.0)
        } else {
            draw_ctx.get_view_params()
        };

        // With filterunits == ObjectBoundingBox, lengths represent fractions or percentages of the
        // referencing node. No units are allowed (it's checked during attribute parsing).
        let (x, y, w, h) = if self.filterunits == CoordUnits::ObjectBoundingBox {
            (
                self.x.length,
                self.y.length,
                self.width.length,
                self.height.length,
            )
        } else {
            (
                self.x.normalize(values, &params),
                self.y.normalize(values, &params),
                self.width.normalize(values, &params),
                self.height.normalize(values, &params),
            )
        };

        let rect = Rect::new(x, y, x + w, y + h);
        let other_bbox = BoundingBox::new().with_transform(transform).with_rect(rect);

        // At this point all of the previous viewbox and matrix business gets converted to pixel
        // coordinates in the final surface, because bbox is created with an identity transform.
        bbox.insert(&other_bbox);

        // Finally, clip to the width and height of our surface.
        let rect = Rect::from_size(width, height);
        let other_bbox = BoundingBox::new().with_rect(rect);
        bbox.clip(&other_bbox);

        bbox
    }
}

impl SetAttributes for Filter {
    fn set_attributes(&mut self, pbag: &PropertyBag<'_>) -> ElementResult {
        // Parse filterUnits first as it affects x, y, width, height checks.
        let result = pbag
            .iter()
            .find(|(attr, _)| attr.expanded() == expanded_name!("", "filterUnits"))
            .and_then(|(attr, value)| attr.parse(value).ok());
        if let Some(filter_units) = result {
            self.filterunits = filter_units
        }

        // With ObjectBoundingBox, only fractions and percents are allowed.
        let no_units_allowed = self.filterunits == CoordUnits::ObjectBoundingBox;

        let check_units_horizontal = |length: Length<Horizontal>| {
            if !no_units_allowed {
                return Ok(length);
            }

            match length.unit {
                LengthUnit::Px | LengthUnit::Percent => Ok(length),
                _ => Err(ValueErrorKind::parse_error(
                    "unit identifiers are not allowed with filterUnits set to objectBoundingBox",
                )),
            }
        };

        let check_units_vertical = |length: Length<Vertical>| {
            if !no_units_allowed {
                return Ok(length);
            }

            match length.unit {
                LengthUnit::Px | LengthUnit::Percent => Ok(length),
                _ => Err(ValueErrorKind::parse_error(
                    "unit identifiers are not allowed with filterUnits set to objectBoundingBox",
                )),
            }
        };

        let check_units_horizontal_and_ensure_nonnegative = |length: Length<Horizontal>| {
            check_units_horizontal(length).and_then(Length::<Horizontal>::check_nonnegative)
        };

        let check_units_vertical_and_ensure_nonnegative = |length: Length<Vertical>| {
            check_units_vertical(length).and_then(Length::<Vertical>::check_nonnegative)
        };

        // Parse the rest of the attributes.
        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!("", "x") => {
                    self.x = attr.parse_and_validate(value, check_units_horizontal)?
                }
                expanded_name!("", "y") => {
                    self.y = attr.parse_and_validate(value, check_units_vertical)?
                }
                expanded_name!("", "width") => {
                    self.width = attr
                        .parse_and_validate(value, check_units_horizontal_and_ensure_nonnegative)?
                }
                expanded_name!("", "height") => {
                    self.height =
                        attr.parse_and_validate(value, check_units_vertical_and_ensure_nonnegative)?
                }
                expanded_name!("", "primitiveUnits") => self.primitiveunits = attr.parse(value)?,
                _ => (),
            }
        }

        Ok(())
    }
}

impl Draw for Filter {}

#[derive(Debug, Clone, PartialEq)]
pub enum FilterValue {
    URL(Fragment),
}
#[derive(Debug, Clone, PartialEq)]
pub struct FilterValueList(pub Vec<FilterValue>);

impl Default for FilterValueList {
    fn default() -> FilterValueList {
        FilterValueList(vec![])
    }
}

impl FilterValueList {
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Check that at least one filter URI exists and that all contained
    /// URIs reference existing <filter> elements.
    pub fn is_applicable(&self, node: &Node, acquired_nodes: &mut AcquiredNodes) -> bool {
        if self.is_empty() {
            return false;
        }

        self.0.iter().all(|filter| match filter {
            FilterValue::URL(filter_uri) => match acquired_nodes.acquire(filter_uri) {
                Ok(acquired) => {
                    let filter_node = acquired.get();

                    match *filter_node.borrow_element() {
                        Element::Filter(_) => true,
                        _ => {
                            rsvg_log!(
                                "element {} will not be filtered since \"{}\" is not a filter",
                                node,
                                filter_uri,
                            );
                            false
                        }
                    }
                }
                _ => {
                    rsvg_log!(
                        "element {} will not be filtered since its filter \"{}\" was not found",
                        node,
                        filter_uri,
                    );
                    false
                }
            },
        })
    }
}

impl Parse for FilterValueList {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, crate::error::ParseError<'i>> {
        let mut result = FilterValueList::default();

        if parser
            .try_parse(|p| p.expect_ident_matching("none"))
            .is_ok()
        {
            return Ok(result);
        }

        while !parser.is_exhausted() {
            let loc = parser.current_source_location();

            if let Ok(IRI::Resource(uri)) = IRI::parse(parser) {
                result.0.push(FilterValue::URL(uri));
            } else {
                let token = parser.next()?;
                return Err(loc.new_basic_unexpected_token_error(token.clone()).into());
            }
        }

        Ok(result)
    }
}

#[cfg(test)]
#[test]
fn parses_filter_value_list() {
    use crate::allowed_url::Fragment;
    use crate::filter::FilterValue;

    assert_eq!(
        FilterValueList::parse_str("none"),
        Ok(FilterValueList::default())
    );

    let f1 = Fragment::new(Some("foo.svg".to_string()), "bar".to_string());
    let f2 = Fragment::new(Some("test.svg".to_string()), "baz".to_string());
    assert_eq!(
        FilterValueList::parse_str("url(foo.svg#bar) url(test.svg#baz)"),
        Ok(FilterValueList(vec![
            FilterValue::URL(f1),
            FilterValue::URL(f2)
        ]))
    );

    assert!(FilterValueList::parse_str("fail").is_err());
    assert!(FilterValueList::parse_str("url(#test) none").is_err());
}
<commit_msg>Split FilterValueList tests between valid and invalid syntax<commit_after>//! The `filter` element.

use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::allowed_url::Fragment;
use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, Element, ElementResult, SetAttributes};
use crate::error::ValueErrorKind;
use crate::iri::IRI;
use crate::length::*;
use crate::node::{Node, NodeBorrow};
use crate::parsers::{Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_bag::PropertyBag;
use crate::rect::Rect;
use crate::transform::Transform;

/// The <filter> node.
pub struct Filter {
    x: Length<Horizontal>,
    y: Length<Vertical>,
    width: Length<Horizontal>,
    height: Length<Vertical>,
    filterunits: CoordUnits,
    primitiveunits: CoordUnits,
}

impl Default for Filter {
    /// Constructs a new `Filter` with default properties.
    fn default() -> Self {
        Self {
            x: Length::<Horizontal>::parse_str("-10%").unwrap(),
            y: Length::<Vertical>::parse_str("-10%").unwrap(),
            width: Length::<Horizontal>::parse_str("120%").unwrap(),
            height: Length::<Vertical>::parse_str("120%").unwrap(),
            filterunits: CoordUnits::ObjectBoundingBox,
            primitiveunits: CoordUnits::UserSpaceOnUse,
        }
    }
}

impl Filter {
    pub fn get_filter_units(&self) -> CoordUnits {
        self.filterunits
    }

    pub fn get_primitive_units(&self) -> CoordUnits {
        self.primitiveunits
    }

    /// Computes and returns the filter effects region.
    pub fn compute_effects_region(
        &self,
        computed_from_target_node: &ComputedValues,
        draw_ctx: &mut DrawingCtx,
        transform: Transform,
        width: f64,
        height: f64,
    ) -> BoundingBox {
        // Filters use the properties of the target node.
        let values = computed_from_target_node;

        let mut bbox = BoundingBox::new();

        // transform is set up in FilterContext::new() in such a way that for
        // filterunits == ObjectBoundingBox it includes scaling to correct width, height and
        // this is why width and height are set to 1, 1 (and for filterunits ==
        // UserSpaceOnUse, transform doesn't include scaling because in this case the correct
        // width, height already happens to be the viewbox width, height).
        //
        // It's done this way because with ObjectBoundingBox, non-percentage values are supposed to
        // represent the fractions of the referenced node, and with width and height = 1, 1 this
        // works out exactly like that.
        let params = if self.filterunits == CoordUnits::ObjectBoundingBox {
            draw_ctx.push_view_box(1.0, 1.0)
        } else {
            draw_ctx.get_view_params()
        };

        // With filterunits == ObjectBoundingBox, lengths represent fractions or percentages of the
        // referencing node. No units are allowed (it's checked during attribute parsing).
        let (x, y, w, h) = if self.filterunits == CoordUnits::ObjectBoundingBox {
            (
                self.x.length,
                self.y.length,
                self.width.length,
                self.height.length,
            )
        } else {
            (
                self.x.normalize(values, &params),
                self.y.normalize(values, &params),
                self.width.normalize(values, &params),
                self.height.normalize(values, &params),
            )
        };

        let rect = Rect::new(x, y, x + w, y + h);
        let other_bbox = BoundingBox::new().with_transform(transform).with_rect(rect);

        // At this point all of the previous viewbox and matrix business gets converted to pixel
        // coordinates in the final surface, because bbox is created with an identity transform.
        bbox.insert(&other_bbox);

        // Finally, clip to the width and height of our surface.
        let rect = Rect::from_size(width, height);
        let other_bbox = BoundingBox::new().with_rect(rect);
        bbox.clip(&other_bbox);

        bbox
    }
}

impl SetAttributes for Filter {
    fn set_attributes(&mut self, pbag: &PropertyBag<'_>) -> ElementResult {
        // Parse filterUnits first as it affects x, y, width, height checks.
        let result = pbag
            .iter()
            .find(|(attr, _)| attr.expanded() == expanded_name!("", "filterUnits"))
            .and_then(|(attr, value)| attr.parse(value).ok());
        if let Some(filter_units) = result {
            self.filterunits = filter_units
        }

        // With ObjectBoundingBox, only fractions and percents are allowed.
        let no_units_allowed = self.filterunits == CoordUnits::ObjectBoundingBox;

        let check_units_horizontal = |length: Length<Horizontal>| {
            if !no_units_allowed {
                return Ok(length);
            }

            match length.unit {
                LengthUnit::Px | LengthUnit::Percent => Ok(length),
                _ => Err(ValueErrorKind::parse_error(
                    "unit identifiers are not allowed with filterUnits set to objectBoundingBox",
                )),
            }
        };

        let check_units_vertical = |length: Length<Vertical>| {
            if !no_units_allowed {
                return Ok(length);
            }

            match length.unit {
                LengthUnit::Px | LengthUnit::Percent => Ok(length),
                _ => Err(ValueErrorKind::parse_error(
                    "unit identifiers are not allowed with filterUnits set to objectBoundingBox",
                )),
            }
        };

        let check_units_horizontal_and_ensure_nonnegative = |length: Length<Horizontal>| {
            check_units_horizontal(length).and_then(Length::<Horizontal>::check_nonnegative)
        };

        let check_units_vertical_and_ensure_nonnegative = |length: Length<Vertical>| {
            check_units_vertical(length).and_then(Length::<Vertical>::check_nonnegative)
        };

        // Parse the rest of the attributes.
        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!("", "x") => {
                    self.x = attr.parse_and_validate(value, check_units_horizontal)?
                }
                expanded_name!("", "y") => {
                    self.y = attr.parse_and_validate(value, check_units_vertical)?
                }
                expanded_name!("", "width") => {
                    self.width = attr
                        .parse_and_validate(value, check_units_horizontal_and_ensure_nonnegative)?
                }
                expanded_name!("", "height") => {
                    self.height =
                        attr.parse_and_validate(value, check_units_vertical_and_ensure_nonnegative)?
                }
                expanded_name!("", "primitiveUnits") => self.primitiveunits = attr.parse(value)?,
                _ => (),
            }
        }

        Ok(())
    }
}

impl Draw for Filter {}

#[derive(Debug, Clone, PartialEq)]
pub enum FilterValue {
    URL(Fragment),
}
#[derive(Debug, Clone, PartialEq)]
pub struct FilterValueList(pub Vec<FilterValue>);

impl Default for FilterValueList {
    fn default() -> FilterValueList {
        FilterValueList(vec![])
    }
}

impl FilterValueList {
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Check that at least one filter URI exists and that all contained
    /// URIs reference existing <filter> elements.
    pub fn is_applicable(&self, node: &Node, acquired_nodes: &mut AcquiredNodes) -> bool {
        if self.is_empty() {
            return false;
        }

        self.0.iter().all(|filter| match filter {
            FilterValue::URL(filter_uri) => match acquired_nodes.acquire(filter_uri) {
                Ok(acquired) => {
                    let filter_node = acquired.get();

                    match *filter_node.borrow_element() {
                        Element::Filter(_) => true,
                        _ => {
                            rsvg_log!(
                                "element {} will not be filtered since \"{}\" is not a filter",
                                node,
                                filter_uri,
                            );
                            false
                        }
                    }
                }
                _ => {
                    rsvg_log!(
                        "element {} will not be filtered since its filter \"{}\" was not found",
                        node,
                        filter_uri,
                    );
                    false
                }
            },
        })
    }
}

impl Parse for FilterValueList {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, crate::error::ParseError<'i>> {
        let mut result = FilterValueList::default();

        if parser
            .try_parse(|p| p.expect_ident_matching("none"))
            .is_ok()
        {
            return Ok(result);
        }

        while !parser.is_exhausted() {
            let loc = parser.current_source_location();

            if let Ok(IRI::Resource(uri)) = IRI::parse(parser) {
                result.0.push(FilterValue::URL(uri));
            } else {
                let token = parser.next()?;
                return Err(loc.new_basic_unexpected_token_error(token.clone()).into());
            }
        }

        Ok(result)
    }
}

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

    #[test]
    fn parses_filter_value_list() {
        assert_eq!(
            FilterValueList::parse_str("none"),
            Ok(FilterValueList::default())
        );

        let f1 = Fragment::new(Some("foo.svg".to_string()), "bar".to_string());
        let f2 = Fragment::new(Some("test.svg".to_string()), "baz".to_string());
        assert_eq!(
            FilterValueList::parse_str("url(foo.svg#bar) url(test.svg#baz)"),
            Ok(FilterValueList(vec![
                FilterValue::URL(f1),
                FilterValue::URL(f2)
            ]))
        );
    }

    #[test]
    fn detects_invalid_filter_value_list() {
        assert!(FilterValueList::parse_str("fail").is_err());
        assert!(FilterValueList::parse_str("url(#test) none").is_err());
    }
}
<|endoftext|>


<commit_before>use kernel::{
    async_trait::async_trait,
    eyre::{bail, Result},
    serde::Serialize,
    stencila_schema::{CodeError, Node},
    Kernel, KernelStatus, KernelTrait,
};
use std::collections::HashMap;

/// A kernel that simply stores nodes
///
/// This kernel is used as the default place to store the value of document
/// parameters. The value of those parameters can then be mirrored to other
/// kernels.
#[derive(Debug, Clone, Default, Serialize)]
#[serde(crate = "kernel::serde")]
pub struct StoreKernel {
    symbols: HashMap<String, Node>,
}

impl StoreKernel {
    pub fn new() -> Self {
        Self::default()
    }
}

#[async_trait]
impl KernelTrait for StoreKernel {
    fn spec(&self) -> Kernel {
        Kernel {
            language: "".to_string(),
        }
    }

    async fn status(&self) -> Result<KernelStatus> {
        Ok(KernelStatus::Idle)
    }

    async fn get(&self, name: &str) -> Result<Node> {
        match self.symbols.get(name) {
            Some(node) => Ok(node.clone()),
            None => bail!("Symbol `{}` does not exist in this kernel", name),
        }
    }

    async fn set(&mut self, name: &str, value: Node) -> Result<()> {
        self.symbols.insert(name.to_string(), value);
        Ok(())
    }

    async fn exec(&mut self, code: &str) -> Result<(Vec<Node>, Vec<CodeError>)> {
        let mut outputs = Vec::new();
        let mut errors = Vec::new();
        for line in code.lines() {
            match self.get(line.trim()).await {
                Ok(output) => outputs.push(output),
                Err(error) => errors.push(CodeError {
                    error_message: error.to_string(),
                    ..Default::default()
                }),
            }
        }
        Ok((outputs, errors))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use kernel::{KernelStatus, KernelTrait};

    #[tokio::test]
    async fn status() -> Result<()> {
        let kernel = StoreKernel::new();

        assert_eq!(kernel.status().await?, KernelStatus::Idle);

        Ok(())
    }

    #[tokio::test]
    async fn get_set_exec() -> Result<()> {
        let mut kernel = StoreKernel::new();

        match kernel.get("a").await {
            Ok(..) => bail!("Expected an error"),
            Err(error) => assert!(error.to_string().contains("does not exist")),
        };

        kernel.set("a", Node::String("A".to_string())).await?;
        kernel.set("b", Node::Number(1.23)).await?;

        let a = kernel.get("a").await?;
        assert!(matches!(a, Node::String(..)));

        let b = kernel.get("b").await?;
        assert!(matches!(b, Node::Number(..)));

        let (outputs, errors) = kernel.exec("a\nb").await?;
        assert_eq!(outputs.len(), 2);
        assert_eq!(errors.len(), 0);

        let (outputs, errors) = kernel.exec("x\ny\nz").await?;
        assert_eq!(outputs.len(), 0);
        assert_eq!(errors.len(), 3);

        Ok(())
    }
}
<commit_msg>fix(Store kernel): Update `get` to be `mut`<commit_after>use kernel::{
    async_trait::async_trait,
    eyre::{bail, Result},
    serde::Serialize,
    stencila_schema::{CodeError, Node},
    Kernel, KernelStatus, KernelTrait,
};
use std::collections::HashMap;

/// A kernel that simply stores nodes
///
/// This kernel is used as the default place to store the value of document
/// parameters. The value of those parameters can then be mirrored to other
/// kernels.
#[derive(Debug, Clone, Default, Serialize)]
#[serde(crate = "kernel::serde")]
pub struct StoreKernel {
    symbols: HashMap<String, Node>,
}

impl StoreKernel {
    pub fn new() -> Self {
        Self::default()
    }
}

#[async_trait]
impl KernelTrait for StoreKernel {
    fn spec(&self) -> Kernel {
        Kernel {
            language: "".to_string(),
        }
    }

    async fn status(&self) -> Result<KernelStatus> {
        Ok(KernelStatus::Idle)
    }

    async fn get(&mut self, name: &str) -> Result<Node> {
        match self.symbols.get(name) {
            Some(node) => Ok(node.clone()),
            None => bail!("Symbol `{}` does not exist in this kernel", name),
        }
    }

    async fn set(&mut self, name: &str, value: Node) -> Result<()> {
        self.symbols.insert(name.to_string(), value);
        Ok(())
    }

    async fn exec(&mut self, code: &str) -> Result<(Vec<Node>, Vec<CodeError>)> {
        let mut outputs = Vec::new();
        let mut errors = Vec::new();
        for line in code.lines() {
            match self.get(line.trim()).await {
                Ok(output) => outputs.push(output),
                Err(error) => errors.push(CodeError {
                    error_message: error.to_string(),
                    ..Default::default()
                }),
            }
        }
        Ok((outputs, errors))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use kernel::{KernelStatus, KernelTrait};

    #[tokio::test]
    async fn status() -> Result<()> {
        let kernel = StoreKernel::new();

        assert_eq!(kernel.status().await?, KernelStatus::Idle);

        Ok(())
    }

    #[tokio::test]
    async fn get_set_exec() -> Result<()> {
        let mut kernel = StoreKernel::new();

        match kernel.get("a").await {
            Ok(..) => bail!("Expected an error"),
            Err(error) => assert!(error.to_string().contains("does not exist")),
        };

        kernel.set("a", Node::String("A".to_string())).await?;
        kernel.set("b", Node::Number(1.23)).await?;

        let a = kernel.get("a").await?;
        assert!(matches!(a, Node::String(..)));

        let b = kernel.get("b").await?;
        assert!(matches!(b, Node::Number(..)));

        let (outputs, errors) = kernel.exec("a\nb").await?;
        assert_eq!(outputs.len(), 2);
        assert_eq!(errors.len(), 0);

        let (outputs, errors) = kernel.exec("x\ny\nz").await?;
        assert_eq!(outputs.len(), 0);
        assert_eq!(errors.len(), 3);

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