<commit_before>//! A small TCP server to handle collection of diagnostics information in a
//! cross-platform way for the `cargo fix` command.

use std::collections::HashSet;
use std::env;
use std::io::{BufReader, Read, Write};
use std::net::{Shutdown, SocketAddr, TcpListener, TcpStream};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::{self, JoinHandle};

use failure::{Error, ResultExt};
use serde_json;

use util::{Config, ProcessBuilder};
use util::errors::CargoResult;

const DIAGNOSICS_SERVER_VAR: &str = "__CARGO_FIX_DIAGNOSTICS_SERVER";
const PLEASE_REPORT_THIS_BUG: &str =
    "\
     This likely indicates a bug in either rustc or cargo itself,\n\
     and we would appreciate a bug report! You're likely to see \n\
     a number of compiler warnings after this message which cargo\n\
     attempted to fix but failed. If you could open an issue at\n\
     https://github.com/rust-lang/cargo/issues\n\
     quoting the full output of this command we'd be very appreciative!\n\n\
     ";

#[derive(Deserialize, Serialize)]
pub enum Message {
    Fixing {
        file: String,
        fixes: u32,
    },
    FixFailed {
        files: Vec<String>,
        krate: Option<String>,
    },
    ReplaceFailed {
        file: String,
        message: String,
    },
    EditionAlreadyEnabled {
        file: String,
        edition: String,
    },
    IdiomEditionMismatch {
        file: String,
        idioms: String,
        edition: Option<String>,
    },
}

impl Message {
    pub fn post(&self) -> Result<(), Error> {
        let addr = env::var(DIAGNOSICS_SERVER_VAR)
            .context("diagnostics collector misconfigured")?;
        let mut client =
            TcpStream::connect(&addr).context("failed to connect to parent diagnostics target")?;

        let s = serde_json::to_string(self).context("failed to serialize message")?;
        client
            .write_all(s.as_bytes())
            .context("failed to write message to diagnostics target")?;
        client
            .shutdown(Shutdown::Write)
            .context("failed to shutdown")?;

        let mut tmp = Vec::new();
        client
            .read_to_end(&mut tmp)
            .context("failed to receive a disconnect")?;

        Ok(())
    }
}

pub struct DiagnosticPrinter<'a> {
    config: &'a Config,
    edition_already_enabled: HashSet<String>,
    idiom_mismatch: HashSet<String>,
}

impl<'a> DiagnosticPrinter<'a> {
    pub fn new(config: &'a Config) -> DiagnosticPrinter<'a> {
        DiagnosticPrinter {
            config,
            edition_already_enabled: HashSet::new(),
            idiom_mismatch: HashSet::new(),
        }
    }

    pub fn print(&mut self, msg: &Message) -> CargoResult<()> {
        match msg {
            Message::Fixing { file, fixes } => {
                let msg = if *fixes == 1 { "fix" } else { "fixes" };
                let msg = format!("{} ({} {})", file, fixes, msg);
                self.config.shell().status("Fixing", msg)
            }
            Message::ReplaceFailed { file, message } => {
                let msg = format!("error applying suggestions to `{}`\n", file);
                self.config.shell().warn(&msg)?;
                write!(
                    self.config.shell().err(),
                    "The full error message was:\n\n> {}\n\n",
                    message,
                )?;
                write!(self.config.shell().err(), "{}", PLEASE_REPORT_THIS_BUG)?;
                Ok(())
            }
            Message::FixFailed { files, krate } => {
                if let Some(ref krate) = *krate {
                    self.config.shell().warn(&format!(
                        "failed to automatically apply fixes suggested by rustc \
                         to crate `{}`",
                        krate,
                    ))?;
                } else {
                    self.config.shell().warn(
                        "failed to automatically apply fixes suggested by rustc"
                    )?;
                }
                if !files.is_empty() {
                    writeln!(
                        self.config.shell().err(),
                        "\nafter fixes were automatically applied the compiler \
                         reported errors within these files:\n"
                    )?;
                    for file in files {
                        writeln!(self.config.shell().err(), "  * {}", file)?;
                    }
                    writeln!(self.config.shell().err())?;
                }
                write!(self.config.shell().err(), "{}", PLEASE_REPORT_THIS_BUG)?;
                Ok(())
            }
            Message::EditionAlreadyEnabled { file, edition } => {
                // Like above, only warn once per file
                if !self.edition_already_enabled.insert(file.clone()) {
                    return Ok(())
                }

                let msg = format!(
                    "\
cannot prepare for the {} edition when it is enabled, so cargo cannot
automatically fix errors in `{}`

To prepare for the {0} edition you should first remove `edition = '{0}'` from
your `Cargo.toml` and then rerun this command. Once all warnings have been fixed
then you can re-enable the `edition` key in `Cargo.toml`. For some more
information about transitioning to the {0} edition see:

  https://rust-lang-nursery.github.io/edition-guide/editions/transitioning-your-code-to-a-new-edition.html
",
                    edition,
                    file,
                );
                self.config.shell().error(&msg)?;
                Ok(())
            }
            Message::IdiomEditionMismatch { file, idioms, edition } => {
                // Same as above
                if !self.idiom_mismatch.insert(file.clone()) {
                    return Ok(())
                }
                self.config.shell().error(&format!(
                    "\
cannot migrate to the idioms of the {} edition for `{}`
because it is compiled {}, which doesn't match {0}

consider migrating to the {0} edition by adding `edition = '{0}'` to
`Cargo.toml` and then rerunning this command; a more detailed transition
guide can be found at

  https://rust-lang-nursery.github.io/edition-guide/editions/transitioning-your-code-to-a-new-edition.html
",
                    idioms,
                    file,
                    match edition {
                        Some(s) => format!("with the {} edition", s),
                        None => "without an edition".to_string(),
                    },
                ))?;
                Ok(())
            }
        }
    }
}

#[derive(Debug)]
pub struct RustfixDiagnosticServer {
    listener: TcpListener,
    addr: SocketAddr,
}

pub struct StartedServer {
    addr: SocketAddr,
    done: Arc<AtomicBool>,
    thread: Option<JoinHandle<()>>,
}

impl RustfixDiagnosticServer {
    pub fn new() -> Result<Self, Error> {
        let listener = TcpListener::bind("127.0.0.1:0")
            .with_context(|_| "failed to bind TCP listener to manage locking")?;
        let addr = listener.local_addr()?;

        Ok(RustfixDiagnosticServer { listener, addr })
    }

    pub fn configure(&self, process: &mut ProcessBuilder) {
        process.env(DIAGNOSICS_SERVER_VAR, self.addr.to_string());
    }

    pub fn start<F>(self, on_message: F) -> Result<StartedServer, Error>
    where
        F: Fn(Message) + Send + 'static,
    {
        let addr = self.addr;
        let done = Arc::new(AtomicBool::new(false));
        let done2 = done.clone();
        let thread = thread::spawn(move || {
            self.run(&on_message, &done2);
        });

        Ok(StartedServer {
            addr,
            thread: Some(thread),
            done,
        })
    }

    fn run(self, on_message: &Fn(Message), done: &AtomicBool) {
        while let Ok((client, _)) = self.listener.accept() {
            let client = BufReader::new(client);
            match serde_json::from_reader(client) {
                Ok(message) => on_message(message),
                Err(e) => warn!("invalid diagnostics message: {}", e),
            }
            if done.load(Ordering::SeqCst) {
                break
            }
        }
    }
}

impl Drop for StartedServer {
    fn drop(&mut self) {
        self.done.store(true, Ordering::SeqCst);
        // Ignore errors here as this is largely best-effort
        if TcpStream::connect(&self.addr).is_err() {
            return;
        }
        drop(self.thread.take().unwrap().join());
    }
}
<commit_msg>Auto merge of #6071 - orium:fix-links, r=alexcrichton<commit_after>//! A small TCP server to handle collection of diagnostics information in a
//! cross-platform way for the `cargo fix` command.

use std::collections::HashSet;
use std::env;
use std::io::{BufReader, Read, Write};
use std::net::{Shutdown, SocketAddr, TcpListener, TcpStream};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::{self, JoinHandle};

use failure::{Error, ResultExt};
use serde_json;

use util::{Config, ProcessBuilder};
use util::errors::CargoResult;

const DIAGNOSICS_SERVER_VAR: &str = "__CARGO_FIX_DIAGNOSTICS_SERVER";
const PLEASE_REPORT_THIS_BUG: &str =
    "\
     This likely indicates a bug in either rustc or cargo itself,\n\
     and we would appreciate a bug report! You're likely to see \n\
     a number of compiler warnings after this message which cargo\n\
     attempted to fix but failed. If you could open an issue at\n\
     https://github.com/rust-lang/cargo/issues\n\
     quoting the full output of this command we'd be very appreciative!\n\n\
     ";

#[derive(Deserialize, Serialize)]
pub enum Message {
    Fixing {
        file: String,
        fixes: u32,
    },
    FixFailed {
        files: Vec<String>,
        krate: Option<String>,
    },
    ReplaceFailed {
        file: String,
        message: String,
    },
    EditionAlreadyEnabled {
        file: String,
        edition: String,
    },
    IdiomEditionMismatch {
        file: String,
        idioms: String,
        edition: Option<String>,
    },
}

impl Message {
    pub fn post(&self) -> Result<(), Error> {
        let addr = env::var(DIAGNOSICS_SERVER_VAR)
            .context("diagnostics collector misconfigured")?;
        let mut client =
            TcpStream::connect(&addr).context("failed to connect to parent diagnostics target")?;

        let s = serde_json::to_string(self).context("failed to serialize message")?;
        client
            .write_all(s.as_bytes())
            .context("failed to write message to diagnostics target")?;
        client
            .shutdown(Shutdown::Write)
            .context("failed to shutdown")?;

        let mut tmp = Vec::new();
        client
            .read_to_end(&mut tmp)
            .context("failed to receive a disconnect")?;

        Ok(())
    }
}

pub struct DiagnosticPrinter<'a> {
    config: &'a Config,
    edition_already_enabled: HashSet<String>,
    idiom_mismatch: HashSet<String>,
}

impl<'a> DiagnosticPrinter<'a> {
    pub fn new(config: &'a Config) -> DiagnosticPrinter<'a> {
        DiagnosticPrinter {
            config,
            edition_already_enabled: HashSet::new(),
            idiom_mismatch: HashSet::new(),
        }
    }

    pub fn print(&mut self, msg: &Message) -> CargoResult<()> {
        match msg {
            Message::Fixing { file, fixes } => {
                let msg = if *fixes == 1 { "fix" } else { "fixes" };
                let msg = format!("{} ({} {})", file, fixes, msg);
                self.config.shell().status("Fixing", msg)
            }
            Message::ReplaceFailed { file, message } => {
                let msg = format!("error applying suggestions to `{}`\n", file);
                self.config.shell().warn(&msg)?;
                write!(
                    self.config.shell().err(),
                    "The full error message was:\n\n> {}\n\n",
                    message,
                )?;
                write!(self.config.shell().err(), "{}", PLEASE_REPORT_THIS_BUG)?;
                Ok(())
            }
            Message::FixFailed { files, krate } => {
                if let Some(ref krate) = *krate {
                    self.config.shell().warn(&format!(
                        "failed to automatically apply fixes suggested by rustc \
                         to crate `{}`",
                        krate,
                    ))?;
                } else {
                    self.config.shell().warn(
                        "failed to automatically apply fixes suggested by rustc"
                    )?;
                }
                if !files.is_empty() {
                    writeln!(
                        self.config.shell().err(),
                        "\nafter fixes were automatically applied the compiler \
                         reported errors within these files:\n"
                    )?;
                    for file in files {
                        writeln!(self.config.shell().err(), "  * {}", file)?;
                    }
                    writeln!(self.config.shell().err())?;
                }
                write!(self.config.shell().err(), "{}", PLEASE_REPORT_THIS_BUG)?;
                Ok(())
            }
            Message::EditionAlreadyEnabled { file, edition } => {
                // Like above, only warn once per file
                if !self.edition_already_enabled.insert(file.clone()) {
                    return Ok(())
                }

                let msg = format!(
                    "\
cannot prepare for the {} edition when it is enabled, so cargo cannot
automatically fix errors in `{}`

To prepare for the {0} edition you should first remove `edition = '{0}'` from
your `Cargo.toml` and then rerun this command. Once all warnings have been fixed
then you can re-enable the `edition` key in `Cargo.toml`. For some more
information about transitioning to the {0} edition see:

  https://rust-lang-nursery.github.io/edition-guide/editions/transitioning-an-existing-project-to-a-new-edition.html
",
                    edition,
                    file,
                );
                self.config.shell().error(&msg)?;
                Ok(())
            }
            Message::IdiomEditionMismatch { file, idioms, edition } => {
                // Same as above
                if !self.idiom_mismatch.insert(file.clone()) {
                    return Ok(())
                }
                self.config.shell().error(&format!(
                    "\
cannot migrate to the idioms of the {} edition for `{}`
because it is compiled {}, which doesn't match {0}

consider migrating to the {0} edition by adding `edition = '{0}'` to
`Cargo.toml` and then rerunning this command; a more detailed transition
guide can be found at

  https://rust-lang-nursery.github.io/edition-guide/editions/transitioning-an-existing-project-to-a-new-edition.html
",
                    idioms,
                    file,
                    match edition {
                        Some(s) => format!("with the {} edition", s),
                        None => "without an edition".to_string(),
                    },
                ))?;
                Ok(())
            }
        }
    }
}

#[derive(Debug)]
pub struct RustfixDiagnosticServer {
    listener: TcpListener,
    addr: SocketAddr,
}

pub struct StartedServer {
    addr: SocketAddr,
    done: Arc<AtomicBool>,
    thread: Option<JoinHandle<()>>,
}

impl RustfixDiagnosticServer {
    pub fn new() -> Result<Self, Error> {
        let listener = TcpListener::bind("127.0.0.1:0")
            .with_context(|_| "failed to bind TCP listener to manage locking")?;
        let addr = listener.local_addr()?;

        Ok(RustfixDiagnosticServer { listener, addr })
    }

    pub fn configure(&self, process: &mut ProcessBuilder) {
        process.env(DIAGNOSICS_SERVER_VAR, self.addr.to_string());
    }

    pub fn start<F>(self, on_message: F) -> Result<StartedServer, Error>
    where
        F: Fn(Message) + Send + 'static,
    {
        let addr = self.addr;
        let done = Arc::new(AtomicBool::new(false));
        let done2 = done.clone();
        let thread = thread::spawn(move || {
            self.run(&on_message, &done2);
        });

        Ok(StartedServer {
            addr,
            thread: Some(thread),
            done,
        })
    }

    fn run(self, on_message: &Fn(Message), done: &AtomicBool) {
        while let Ok((client, _)) = self.listener.accept() {
            let client = BufReader::new(client);
            match serde_json::from_reader(client) {
                Ok(message) => on_message(message),
                Err(e) => warn!("invalid diagnostics message: {}", e),
            }
            if done.load(Ordering::SeqCst) {
                break
            }
        }
    }
}

impl Drop for StartedServer {
    fn drop(&mut self) {
        self.done.store(true, Ordering::SeqCst);
        // Ignore errors here as this is largely best-effort
        if TcpStream::connect(&self.addr).is_err() {
            return;
        }
        drop(self.thread.take().unwrap().join());
    }
}
<|endoftext|>


<commit_before>extern crate react;

use react::*;

#[test]
fn input_cells_have_a_value() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(10);
    assert_eq!(reactor.value(input), Some(10));
}

#[test]
#[ignore]
fn an_input_cells_value_can_be_set() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(4);
    assert!(reactor.set_value(input, 20).is_ok());
    assert_eq!(reactor.value(input), Some(20));
}

#[test]
#[ignore]
fn error_setting_a_nonexistent_input_cell() {
    let mut dummy_reactor = Reactor::new();
    let input = dummy_reactor.create_input(1);
    assert!(Reactor::new().set_value(input, 0).is_err());
}

#[test]
#[ignore]
fn compute_cells_calculate_initial_value() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
    assert_eq!(reactor.value(output), Some(2));
}

#[test]
#[ignore]
fn compute_cells_take_inputs_in_the_right_order() {
    let mut reactor = Reactor::new();
    let one = reactor.create_input(1);
    let two = reactor.create_input(2);
    let output = reactor.create_compute(&[one, two], |v| v[0] + v[1] * 10).unwrap();
    assert_eq!(reactor.value(output), Some(21));
}

#[test]
#[ignore]
fn error_creating_compute_cell_if_input_doesnt_exist() {
    let mut dummy_reactor = Reactor::new();
    let input = dummy_reactor.create_input(1);
    assert!(Reactor::new().create_compute(&[input], |_| 0).is_err());
}

#[test]
#[ignore]
fn do_not_break_cell_if_creating_compute_cell_with_valid_and_invalid_input() {
    let mut dummy_reactor = Reactor::new();
    let _ = dummy_reactor.create_input(1);
    let dummy_cell = dummy_reactor.create_input(2);
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    assert!(reactor.create_compute(&[input, dummy_cell], |_| 0).is_err());
    assert!(reactor.set_value(input, 5).is_ok());
    assert_eq!(reactor.value(input), Some(5));
}

#[test]
#[ignore]
fn compute_cells_update_value_when_dependencies_are_changed() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
    assert_eq!(reactor.value(output), Some(2));
    assert!(reactor.set_value(input, 3).is_ok());
    assert_eq!(reactor.value(output), Some(4));
}

#[test]
#[ignore]
fn compute_cells_can_depend_on_other_compute_cells() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let times_two = reactor.create_compute(&[input], |v| v[0] * 2).unwrap();
    let times_thirty = reactor.create_compute(&[input], |v| v[0] * 30).unwrap();
    let output = reactor.create_compute(&[times_two, times_thirty], |v| v[0] + v[1]).unwrap();
    assert_eq!(reactor.value(output), Some(32));
    assert!(reactor.set_value(input, 3).is_ok());
    assert_eq!(reactor.value(output), Some(96));
}

#[test]
#[ignore]
fn error_setting_a_compute_cell() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |_| 0).unwrap();
    assert!(reactor.set_value(output, 3).is_err());
}

#[test]
#[ignore]
fn compute_cells_fire_callbacks() {
    // This is a bit awkward, but the closure mutably borrows `values`.
    // So we have to end its borrow by taking reactor out of scope.
    let mut values = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        assert!(reactor.add_callback(output, |v| values.push(v)).is_ok());
        assert!(reactor.set_value(input, 3).is_ok());
    }
    assert_eq!(values, vec![4]);
}

#[test]
#[ignore]
fn error_adding_callback_to_nonexistent_cell() {
    let mut dummy_reactor = Reactor::new();
    let input = dummy_reactor.create_input(1);
    let output = dummy_reactor.create_compute(&[input], |_| 0).unwrap();
    assert!(Reactor::new().add_callback(output, |_: usize| println!("hi")).is_err());
}

#[test]
#[ignore]
fn callbacks_only_fire_on_change() {
    let mut values = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let output = reactor.create_compute(&[input], |v| if v[0] < 3 { 111 } else { 222 }).unwrap();
        assert!(reactor.add_callback(output, |v| values.push(v)).is_ok());
        assert!(reactor.set_value(input, 2).is_ok());
        assert!(reactor.set_value(input, 4).is_ok());
    }
    assert_eq!(values, vec![222]);
}

#[test]
#[ignore]
fn callbacks_can_be_added_and_removed() {
    let mut values1 = Vec::new();
    let mut values2 = Vec::new();
    let mut values3 = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(11);
        let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        let callback = reactor.add_callback(output, |v| values1.push(v)).unwrap();
        assert!(reactor.add_callback(output, |v| values2.push(v)).is_ok());
        assert!(reactor.set_value(input, 31).is_ok());
        assert!(reactor.remove_callback(output, callback).is_ok());
        assert!(reactor.add_callback(output, |v| values3.push(v)).is_ok());
        assert!(reactor.set_value(input, 41).is_ok());
    }
    assert_eq!(values1, vec![32]);
    assert_eq!(values2, vec![32, 42]);
    assert_eq!(values3, vec![42]);
}

#[test]
#[ignore]
fn removing_a_callback_multiple_times_doesnt_interfere_with_other_callbacks() {
    let mut values1 = Vec::new();
    let mut values2 = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        let callback = reactor.add_callback(output, |v| values1.push(v)).unwrap();
        assert!(reactor.add_callback(output, |v| values2.push(v)).is_ok());
        // We want the first remove to be Ok, but we don't care about the others.
        assert!(reactor.remove_callback(output, callback).is_ok());
        for _ in 1..5 {
            assert!(reactor.remove_callback(output, callback).is_err());
        }
        assert!(reactor.set_value(input, 2).is_ok());
    }
    assert_eq!(values1, Vec::new());
    assert_eq!(values2, vec![3]);
}

#[test]
#[ignore]
fn callbacks_should_only_be_called_once_even_if_multiple_dependencies_change() {
    let mut values = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        let minus_one1 = reactor.create_compute(&[input], |v| v[0] - 1).unwrap();
        let minus_one2 = reactor.create_compute(&[minus_one1], |v| v[0] - 1).unwrap();
        let output = reactor.create_compute(&[plus_one, minus_one2], |v| v[0] * v[1]).unwrap();
        assert!(reactor.add_callback(output, |v| values.push(v)).is_ok());
        assert!(reactor.set_value(input, 4).is_ok());
    }
    assert_eq!(values, vec![10]);
}

#[test]
#[ignore]
fn callbacks_should_not_be_called_if_dependencies_change_but_output_value_doesnt_change() {
    let mut values = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        let minus_one = reactor.create_compute(&[input], |v| v[0] - 1).unwrap();
        let always_two = reactor.create_compute(&[plus_one, minus_one], |v| v[0] - v[1]).unwrap();
        assert!(reactor.add_callback(always_two, |v| values.push(v)).is_ok());
        for i in 2..5 {
            assert!(reactor.set_value(input, i).is_ok());
        }
    }
    assert_eq!(values, Vec::new());
}

#[test]
#[ignore]
fn test_adder_with_boolean_values() {
    // This is a digital logic circuit called an adder:
    // https://en.wikipedia.org/wiki/Adder_(electronics)
    let mut reactor = Reactor::new();
    let a = reactor.create_input(false);
    let b = reactor.create_input(false);
    let carry_in = reactor.create_input(false);

    let a_xor_b = reactor.create_compute(&[a, b], |v| v[0] ^ v[1]).unwrap();
    let sum = reactor.create_compute(&[a_xor_b, carry_in], |v| v[0] ^ v[1]).unwrap();

    let a_xor_b_and_cin = reactor.create_compute(&[a_xor_b, carry_in], |v| v[0] && v[1]).unwrap();
    let a_and_b = reactor.create_compute(&[a, b], |v| v[0] && v[1]).unwrap();
    let carry_out = reactor.create_compute(&[a_xor_b_and_cin, a_and_b], |v| v[0] || v[1]).unwrap();

    let tests = vec![
        (false, false, false, false, false),
        (false, false, true, false, true),
        (false, true, false, false, true),
        (false, true, true, true, false),
        (true, false, false, false, true),
        (true, false, true, true, false),
        (true, true, false, true, false),
        (true, true, true, true, true),
    ];

    for (aval, bval, cinval, expected_cout, expected_sum) in tests {
        assert!(reactor.set_value(a, aval).is_ok());
        assert!(reactor.set_value(b, bval).is_ok());
        assert!(reactor.set_value(carry_in, cinval).is_ok());

        assert_eq!(reactor.value(sum), Some(expected_sum));
        assert_eq!(reactor.value(carry_out), Some(expected_cout));
    }
}
<commit_msg>react: Use `&[...]` instead of `vec![...]`<commit_after>extern crate react;

use react::*;

#[test]
fn input_cells_have_a_value() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(10);
    assert_eq!(reactor.value(input), Some(10));
}

#[test]
#[ignore]
fn an_input_cells_value_can_be_set() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(4);
    assert!(reactor.set_value(input, 20).is_ok());
    assert_eq!(reactor.value(input), Some(20));
}

#[test]
#[ignore]
fn error_setting_a_nonexistent_input_cell() {
    let mut dummy_reactor = Reactor::new();
    let input = dummy_reactor.create_input(1);
    assert!(Reactor::new().set_value(input, 0).is_err());
}

#[test]
#[ignore]
fn compute_cells_calculate_initial_value() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
    assert_eq!(reactor.value(output), Some(2));
}

#[test]
#[ignore]
fn compute_cells_take_inputs_in_the_right_order() {
    let mut reactor = Reactor::new();
    let one = reactor.create_input(1);
    let two = reactor.create_input(2);
    let output = reactor.create_compute(&[one, two], |v| v[0] + v[1] * 10).unwrap();
    assert_eq!(reactor.value(output), Some(21));
}

#[test]
#[ignore]
fn error_creating_compute_cell_if_input_doesnt_exist() {
    let mut dummy_reactor = Reactor::new();
    let input = dummy_reactor.create_input(1);
    assert!(Reactor::new().create_compute(&[input], |_| 0).is_err());
}

#[test]
#[ignore]
fn do_not_break_cell_if_creating_compute_cell_with_valid_and_invalid_input() {
    let mut dummy_reactor = Reactor::new();
    let _ = dummy_reactor.create_input(1);
    let dummy_cell = dummy_reactor.create_input(2);
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    assert!(reactor.create_compute(&[input, dummy_cell], |_| 0).is_err());
    assert!(reactor.set_value(input, 5).is_ok());
    assert_eq!(reactor.value(input), Some(5));
}

#[test]
#[ignore]
fn compute_cells_update_value_when_dependencies_are_changed() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
    assert_eq!(reactor.value(output), Some(2));
    assert!(reactor.set_value(input, 3).is_ok());
    assert_eq!(reactor.value(output), Some(4));
}

#[test]
#[ignore]
fn compute_cells_can_depend_on_other_compute_cells() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let times_two = reactor.create_compute(&[input], |v| v[0] * 2).unwrap();
    let times_thirty = reactor.create_compute(&[input], |v| v[0] * 30).unwrap();
    let output = reactor.create_compute(&[times_two, times_thirty], |v| v[0] + v[1]).unwrap();
    assert_eq!(reactor.value(output), Some(32));
    assert!(reactor.set_value(input, 3).is_ok());
    assert_eq!(reactor.value(output), Some(96));
}

#[test]
#[ignore]
fn error_setting_a_compute_cell() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |_| 0).unwrap();
    assert!(reactor.set_value(output, 3).is_err());
}

#[test]
#[ignore]
fn compute_cells_fire_callbacks() {
    // This is a bit awkward, but the closure mutably borrows `values`.
    // So we have to end its borrow by taking reactor out of scope.
    let mut values = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        assert!(reactor.add_callback(output, |v| values.push(v)).is_ok());
        assert!(reactor.set_value(input, 3).is_ok());
    }
    assert_eq!(values, vec![4]);
}

#[test]
#[ignore]
fn error_adding_callback_to_nonexistent_cell() {
    let mut dummy_reactor = Reactor::new();
    let input = dummy_reactor.create_input(1);
    let output = dummy_reactor.create_compute(&[input], |_| 0).unwrap();
    assert!(Reactor::new().add_callback(output, |_: usize| println!("hi")).is_err());
}

#[test]
#[ignore]
fn callbacks_only_fire_on_change() {
    let mut values = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let output = reactor.create_compute(&[input], |v| if v[0] < 3 { 111 } else { 222 }).unwrap();
        assert!(reactor.add_callback(output, |v| values.push(v)).is_ok());
        assert!(reactor.set_value(input, 2).is_ok());
        assert!(reactor.set_value(input, 4).is_ok());
    }
    assert_eq!(values, vec![222]);
}

#[test]
#[ignore]
fn callbacks_can_be_added_and_removed() {
    let mut values1 = Vec::new();
    let mut values2 = Vec::new();
    let mut values3 = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(11);
        let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        let callback = reactor.add_callback(output, |v| values1.push(v)).unwrap();
        assert!(reactor.add_callback(output, |v| values2.push(v)).is_ok());
        assert!(reactor.set_value(input, 31).is_ok());
        assert!(reactor.remove_callback(output, callback).is_ok());
        assert!(reactor.add_callback(output, |v| values3.push(v)).is_ok());
        assert!(reactor.set_value(input, 41).is_ok());
    }
    assert_eq!(values1, vec![32]);
    assert_eq!(values2, vec![32, 42]);
    assert_eq!(values3, vec![42]);
}

#[test]
#[ignore]
fn removing_a_callback_multiple_times_doesnt_interfere_with_other_callbacks() {
    let mut values1 = Vec::new();
    let mut values2 = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        let callback = reactor.add_callback(output, |v| values1.push(v)).unwrap();
        assert!(reactor.add_callback(output, |v| values2.push(v)).is_ok());
        // We want the first remove to be Ok, but we don't care about the others.
        assert!(reactor.remove_callback(output, callback).is_ok());
        for _ in 1..5 {
            assert!(reactor.remove_callback(output, callback).is_err());
        }
        assert!(reactor.set_value(input, 2).is_ok());
    }
    assert_eq!(values1, Vec::new());
    assert_eq!(values2, vec![3]);
}

#[test]
#[ignore]
fn callbacks_should_only_be_called_once_even_if_multiple_dependencies_change() {
    let mut values = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        let minus_one1 = reactor.create_compute(&[input], |v| v[0] - 1).unwrap();
        let minus_one2 = reactor.create_compute(&[minus_one1], |v| v[0] - 1).unwrap();
        let output = reactor.create_compute(&[plus_one, minus_one2], |v| v[0] * v[1]).unwrap();
        assert!(reactor.add_callback(output, |v| values.push(v)).is_ok());
        assert!(reactor.set_value(input, 4).is_ok());
    }
    assert_eq!(values, vec![10]);
}

#[test]
#[ignore]
fn callbacks_should_not_be_called_if_dependencies_change_but_output_value_doesnt_change() {
    let mut values = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        let minus_one = reactor.create_compute(&[input], |v| v[0] - 1).unwrap();
        let always_two = reactor.create_compute(&[plus_one, minus_one], |v| v[0] - v[1]).unwrap();
        assert!(reactor.add_callback(always_two, |v| values.push(v)).is_ok());
        for i in 2..5 {
            assert!(reactor.set_value(input, i).is_ok());
        }
    }
    assert_eq!(values, Vec::new());
}

#[test]
#[ignore]
fn test_adder_with_boolean_values() {
    // This is a digital logic circuit called an adder:
    // https://en.wikipedia.org/wiki/Adder_(electronics)
    let mut reactor = Reactor::new();
    let a = reactor.create_input(false);
    let b = reactor.create_input(false);
    let carry_in = reactor.create_input(false);

    let a_xor_b = reactor.create_compute(&[a, b], |v| v[0] ^ v[1]).unwrap();
    let sum = reactor.create_compute(&[a_xor_b, carry_in], |v| v[0] ^ v[1]).unwrap();

    let a_xor_b_and_cin = reactor.create_compute(&[a_xor_b, carry_in], |v| v[0] && v[1]).unwrap();
    let a_and_b = reactor.create_compute(&[a, b], |v| v[0] && v[1]).unwrap();
    let carry_out = reactor.create_compute(&[a_xor_b_and_cin, a_and_b], |v| v[0] || v[1]).unwrap();

    let tests = &[
        (false, false, false, false, false),
        (false, false, true, false, true),
        (false, true, false, false, true),
        (false, true, true, true, false),
        (true, false, false, false, true),
        (true, false, true, true, false),
        (true, true, false, true, false),
        (true, true, true, true, true),
    ];

    for &(aval, bval, cinval, expected_cout, expected_sum) in tests {
        assert!(reactor.set_value(a, aval).is_ok());
        assert!(reactor.set_value(b, bval).is_ok());
        assert!(reactor.set_value(carry_in, cinval).is_ok());

        assert_eq!(reactor.value(sum), Some(expected_sum));
        assert_eq!(reactor.value(carry_out), Some(expected_cout));
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// 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.

//! An implementation of `MemoryDB` database.
use std::sync::{Arc, RwLock, RwLockReadGuard};
use std::clone::Clone;
use std::collections::btree_map::{BTreeMap, Range};
use std::iter::Peekable;

use super::{Database, Snapshot, Patch, Change, Iterator, Iter, Result};

/// Database implementation that stores all the data in memory.
///
/// It's mainly used for testing and not designed to be efficient.
#[derive(Default, Clone, Debug)]
pub struct MemoryDB {
    map: Arc<RwLock<BTreeMap<Vec<u8>, Vec<u8>>>>,
}

/// An iterator over the entries of a `MemoryDB`.
struct MemoryDBIter<'a> {
    iter: Peekable<Range<'a, Vec<u8>, Vec<u8>>>,
    _guard: RwLockReadGuard<'a, BTreeMap<Vec<u8>, Vec<u8>>>
}

impl MemoryDB {
    /// Creates a new, empty database.
    pub fn new() -> MemoryDB {
        MemoryDB { map: Arc::new(RwLock::new(BTreeMap::new())) }
    }
}

impl Database for MemoryDB {
    fn clone(&self) -> Box<Database> {
        Box::new(Clone::clone(self))
    }

    fn snapshot(&self) -> Box<Snapshot> {
        Box::new(Clone::clone(self))
    }

    fn merge(&mut self, patch: Patch) -> Result<()> {
        for (key, change) in patch {
            match change {
                Change::Put(value) => {
                    self.map.write().unwrap().insert(key, value);
                }
                Change::Delete => {
                    self.map.write().unwrap().remove(&key);
                }
            }
        }
        Ok(())
    }
}

impl Snapshot for MemoryDB {
    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
        self.map.read().unwrap().get(key).cloned()
    }

    fn contains(&self, key: &[u8]) -> bool {
        self.map.read().unwrap().contains_key(key)
    }

    fn iter<'a>(&'a self, from: &[u8]) -> Iter<'a> {
        use std::collections::Bound::{Included, Unbounded};
        use std::mem::transmute;
        let range = (Included(from), Unbounded);
        let guard = self.map.read().unwrap();

        Box::new(MemoryDBIter {
            iter: unsafe { transmute(guard.range::<[u8], _>(range).peekable()) },
            _guard: guard
        })
    }
}

impl<'a> Iterator for MemoryDBIter<'a> {
    fn next(&mut self) -> Option<(&[u8], &[u8])> {
        self.iter.next().map(|(k, v)| (k.as_slice(), v.as_slice()))
    }

    fn peek(&mut self) -> Option<(&[u8], &[u8])> {
        self.iter.peek().map(|&(k, v)| (k.as_slice(), v.as_slice()))
    }
}
<commit_msg>Changes for passing rustfmt<commit_after>// Copyright 2017 The Exonum Team
//
// 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.

//! An implementation of `MemoryDB` database.
use std::sync::{Arc, RwLock, RwLockReadGuard};
use std::clone::Clone;
use std::collections::btree_map::{BTreeMap, Range};
use std::iter::Peekable;

use super::{Database, Snapshot, Patch, Change, Iterator, Iter, Result};

/// Database implementation that stores all the data in memory.
///
/// It's mainly used for testing and not designed to be efficient.
#[derive(Default, Clone, Debug)]
pub struct MemoryDB {
    map: Arc<RwLock<BTreeMap<Vec<u8>, Vec<u8>>>>,
}

/// An iterator over the entries of a `MemoryDB`.
struct MemoryDBIter<'a> {
    iter: Peekable<Range<'a, Vec<u8>, Vec<u8>>>,
    _guard: RwLockReadGuard<'a, BTreeMap<Vec<u8>, Vec<u8>>>,
}

impl MemoryDB {
    /// Creates a new, empty database.
    pub fn new() -> MemoryDB {
        MemoryDB { map: Arc::new(RwLock::new(BTreeMap::new())) }
    }
}

impl Database for MemoryDB {
    fn clone(&self) -> Box<Database> {
        Box::new(Clone::clone(self))
    }

    fn snapshot(&self) -> Box<Snapshot> {
        Box::new(Clone::clone(self))
    }

    fn merge(&mut self, patch: Patch) -> Result<()> {
        for (key, change) in patch {
            match change {
                Change::Put(value) => {
                    self.map.write().unwrap().insert(key, value);
                }
                Change::Delete => {
                    self.map.write().unwrap().remove(&key);
                }
            }
        }
        Ok(())
    }
}

impl Snapshot for MemoryDB {
    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
        self.map.read().unwrap().get(key).cloned()
    }

    fn contains(&self, key: &[u8]) -> bool {
        self.map.read().unwrap().contains_key(key)
    }

    fn iter<'a>(&'a self, from: &[u8]) -> Iter<'a> {
        use std::collections::Bound::{Included, Unbounded};
        use std::mem::transmute;
        let range = (Included(from), Unbounded);
        let guard = self.map.read().unwrap();

        Box::new(MemoryDBIter {
            iter: unsafe { transmute(guard.range::<[u8], _>(range).peekable()) },
            _guard: guard,
        })
    }
}

impl<'a> Iterator for MemoryDBIter<'a> {
    fn next(&mut self) -> Option<(&[u8], &[u8])> {
        self.iter.next().map(|(k, v)| (k.as_slice(), v.as_slice()))
    }

    fn peek(&mut self) -> Option<(&[u8], &[u8])> {
        self.iter.peek().map(|&(k, v)| (k.as_slice(), v.as_slice()))
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use layout::box::{RenderBox};
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::flow::{FloatFlow, FlowData};
use layout::model::{MaybeAuto};
use layout::float_context::{FloatContext, PlacementInfo, FloatType};

use std::cell::Cell;
use geom::point::Point2D;
use geom::rect::Rect;
use gfx::display_list::DisplayList;
use gfx::geometry::Au;
use gfx::geometry;
use servo_util::tree::TreeNodeRef;

pub struct FloatFlowData {
    /// Data common to all flows.
    common: FlowData,

    /// The associated render box.
    box: Option<RenderBox>,

    containing_width: Au,

    /// Offset relative to where the parent tried to position this flow
    rel_pos: Point2D<Au>,

    /// Left or right?
    float_type: FloatType,

    /// Index into the box list for inline floats
    index: Option<uint>,

    /// Number of floated children
    floated_children: uint,

}

impl FloatFlowData {
    pub fn new(common: FlowData, float_type: FloatType) -> FloatFlowData {
        FloatFlowData {
            common: common,
            containing_width: Au(0),
            box: None,
            index: None,
            float_type: float_type,
            rel_pos: Point2D(Au(0), Au(0)),
            floated_children: 0,
        }
    }

    pub fn teardown(&mut self) {
        self.common.teardown();
        for box in self.box.iter() {
            box.teardown();
        }
        self.box = None;
        self.index = None;
    }
}

impl FloatFlowData {
    pub fn bubble_widths_float(@mut self, ctx: &LayoutContext) {
        let mut min_width = Au(0);
        let mut pref_width = Au(0);
        let mut num_floats = 0;

        for child_ctx in FloatFlow(self).children() {
            //assert!(child_ctx.starts_block_flow() || child_ctx.starts_inline_flow());

            do child_ctx.with_mut_base |child_node| {
                min_width = geometry::max(min_width, child_node.min_width);
                pref_width = geometry::max(pref_width, child_node.pref_width);
                num_floats = num_floats + child_node.num_floats;
            }
        }

        self.common.num_floats = 1;
        self.floated_children = num_floats;

        self.box.map(|&box| {
            let style = box.style();
            do box.with_model |model| {
                model.compute_borders(style)
            }

            min_width = min_width.add(&box.get_min_width(ctx));
            pref_width = pref_width.add(&box.get_pref_width(ctx));
        });

        self.common.min_width = min_width;
        self.common.pref_width = pref_width;
    }

    pub fn assign_widths_float(@mut self) {
        debug!("assign_widths_float: assigning width for flow %?",  self.common.id);
        // position.size.width is set by parent even though we don't know
        // position.origin yet.
        let mut remaining_width = self.common.position.size.width;
        self.containing_width = remaining_width;
        let mut x_offset = Au(0);

        // Parent usually sets this, but floats are never inorder
        self.common.is_inorder = false;

        for &box in self.box.iter() {
            let style = box.style();
            do box.with_model |model| {
                // Can compute padding here since we know containing block width.
                model.compute_padding(style, remaining_width);

                // Margins for floats are 0 if auto.
                let margin_top = MaybeAuto::from_margin(style.margin_top(),
                                                        remaining_width,
                                                        style.font_size()).specified_or_zero();
                let margin_bottom = MaybeAuto::from_margin(style.margin_bottom(),
                                                           remaining_width,
                                                           style.font_size()).specified_or_zero();
                let margin_left = MaybeAuto::from_margin(style.margin_left(),
                                                         remaining_width,
                                                         style.font_size()).specified_or_zero();
                let margin_right = MaybeAuto::from_margin(style.margin_right(),
                                                          remaining_width,
                                                          style.font_size()).specified_or_zero();

                let shrink_to_fit = geometry::min(self.common.pref_width,
                                                  geometry::max(self.common.min_width,
                                                                remaining_width));

                let width = MaybeAuto::from_width(style.width(),
                                                  remaining_width,
                                                  style.font_size()).specified_or_default(shrink_to_fit);
                debug!("assign_widths_float -- width: %?", width);

                model.margin.top = margin_top;
                model.margin.right = margin_right;
                model.margin.bottom = margin_bottom;
                model.margin.left = margin_left;

                x_offset = model.offset();
                remaining_width = width;
            }

            do box.with_mut_base |base| {
                //The associated box is the border box of this flow
                base.position.origin.x = base.model.margin.left;

                let pb = base.model.padding.left + base.model.padding.right +
                    base.model.border.left + base.model.border.right;
                base.position.size.width = remaining_width + pb;
            }
        }

        self.common.position.size.width = remaining_width;

        let has_inorder_children = self.common.num_floats > 0;
        for kid in FloatFlow(self).children() {
            //assert!(kid.starts_block_flow() || kid.starts_inline_flow());

            do kid.with_mut_base |child_node| {
                child_node.position.origin.x = x_offset;
                child_node.position.size.width = remaining_width;
                child_node.is_inorder = has_inorder_children;

                if !child_node.is_inorder {
                    child_node.floats_in = FloatContext::new(0);
                }
            }
        }
    }

    pub fn assign_height_inorder_float(@mut self) {
        debug!("assign_height_inorder_float: assigning height for float %?", self.common.id);
        // assign_height_float was already called by the traversal function
        // so this is well-defined

        let mut height = Au(0);
        let mut clearance = Au(0);
        let mut full_noncontent_width = Au(0);
        let mut full_noncontent_height = Au(0);

        self.box.map(|&box| {
            height = do box.with_base |base| {
                base.position.size.height
            };
            clearance = match box.clear() {
                None => Au(0),
                Some(clear) => {
                    self.common.floats_in.clearance(clear)
                }
            };

            do box.with_base |base| {
                let noncontent_width = base.model.padding.left + base.model.padding.right +
                    base.model.border.left + base.model.border.right;
                let noncontent_height = base.model.padding.top + base.model.padding.bottom +
                    base.model.border.top + base.model.border.bottom;

                full_noncontent_width = noncontent_width + base.model.margin.left + base.model.margin.right;
                full_noncontent_height = noncontent_height + base.model.margin.top + base.model.margin.bottom;
            }

        });

        let info = PlacementInfo {
            width: self.common.position.size.width + full_noncontent_width,
            height: height + full_noncontent_height,
            ceiling: clearance,
            max_width: self.containing_width,
            f_type: self.float_type,
        };

        // Place the float and return the FloatContext back to the parent flow.
        // After, grab the position and use that to set our position.
        self.common.floats_out = self.common.floats_in.add_float(&info);
        self.rel_pos = self.common.floats_out.last_float_pos();
    }

    pub fn assign_height_float(@mut self, ctx: &mut LayoutContext) {
        debug!("assign_height_float: assigning height for float %?", self.common.id);
        let has_inorder_children = self.common.num_floats > 0;
        if has_inorder_children {
            let mut float_ctx = FloatContext::new(self.floated_children);
            for kid in FloatFlow(self).children() {
                do kid.with_mut_base |child_node| {
                    child_node.floats_in = float_ctx.clone();
                }
                kid.assign_height_inorder(ctx);
                do kid.with_mut_base |child_node| {
                    float_ctx = child_node.floats_out.clone();
                }
            }
        }

        let mut cur_y = Au(0);
        let mut top_offset = Au(0);

        for &box in self.box.iter() {
            do box.with_model |model| {
                top_offset = model.margin.top + model.border.top + model.padding.top;
                cur_y = cur_y + top_offset;
            }
        }

        for kid in FloatFlow(self).children() {
            do kid.with_mut_base |child_node| {
                child_node.position.origin.y = cur_y;
                cur_y = cur_y + child_node.position.size.height;
            };
        }

        let mut height = cur_y - top_offset;

        let mut noncontent_width = Au(0);
        let mut noncontent_height = Au(0);
        self.box.map(|&box| {
            do box.with_mut_base |base| {
                //The associated box is the border box of this flow
                base.position.origin.y = base.model.margin.top;

                noncontent_width = base.model.padding.left + base.model.padding.right +
                    base.model.border.left + base.model.border.right;
                noncontent_height = base.model.padding.top + base.model.padding.bottom +
                    base.model.border.top + base.model.border.bottom;
                base.position.size.height = height + noncontent_height;

            }
        });

        //TODO(eatkinson): compute heights properly using the 'height' property.
        for &box in self.box.iter() {
            let height_prop =
                MaybeAuto::from_height(box.style().height(),
                                       Au(0),
                                       box.style().font_size()).specified_or_zero();

            height = geometry::max(height, height_prop) + noncontent_height;
            debug!("assign_height_float -- height: %?", height);
            do box.with_mut_base |base| {
                base.position.size.height = height;
            }
        }
    }

    pub fn build_display_list_float<E:ExtraDisplayListData>(@mut self,
                                                            builder: &DisplayListBuilder,
                                                            dirty: &Rect<Au>,
                                                            list: &Cell<DisplayList<E>>)
                                                            -> bool {

        let abs_rect = Rect(self.common.abs_position, self.common.position.size);
        if !abs_rect.intersects(dirty) {
            return false;
        }

        let offset = self.common.abs_position + self.rel_pos;
        // add box that starts block context
        self.box.map(|&box| {
            box.build_display_list(builder, dirty, &offset, list)
        });

        // TODO: handle any out-of-flow elements

        // go deeper into the flow tree
        let flow = FloatFlow(self);
        for child in flow.children() {
            do child.with_mut_base |base| {
                base.abs_position = offset + base.position.origin;
            }
        }

        true
    }
}

<commit_msg>auto merge of #739 : ILyoan/servo/acid1_margin, r=metajack<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use layout::box::{RenderBox};
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::flow::{FloatFlow, FlowData};
use layout::model::{MaybeAuto};
use layout::float_context::{FloatContext, PlacementInfo, FloatType};

use std::cell::Cell;
use geom::point::Point2D;
use geom::rect::Rect;
use gfx::display_list::DisplayList;
use gfx::geometry::Au;
use gfx::geometry;
use servo_util::tree::TreeNodeRef;

pub struct FloatFlowData {
    /// Data common to all flows.
    common: FlowData,

    /// The associated render box.
    box: Option<RenderBox>,

    containing_width: Au,

    /// Offset relative to where the parent tried to position this flow
    rel_pos: Point2D<Au>,

    /// Left or right?
    float_type: FloatType,

    /// Index into the box list for inline floats
    index: Option<uint>,

    /// Number of floated children
    floated_children: uint,

}

impl FloatFlowData {
    pub fn new(common: FlowData, float_type: FloatType) -> FloatFlowData {
        FloatFlowData {
            common: common,
            containing_width: Au(0),
            box: None,
            index: None,
            float_type: float_type,
            rel_pos: Point2D(Au(0), Au(0)),
            floated_children: 0,
        }
    }

    pub fn teardown(&mut self) {
        self.common.teardown();
        for box in self.box.iter() {
            box.teardown();
        }
        self.box = None;
        self.index = None;
    }
}

impl FloatFlowData {
    pub fn bubble_widths_float(@mut self, ctx: &LayoutContext) {
        let mut min_width = Au(0);
        let mut pref_width = Au(0);
        let mut num_floats = 0;

        for child_ctx in FloatFlow(self).children() {
            //assert!(child_ctx.starts_block_flow() || child_ctx.starts_inline_flow());

            do child_ctx.with_mut_base |child_node| {
                min_width = geometry::max(min_width, child_node.min_width);
                pref_width = geometry::max(pref_width, child_node.pref_width);
                num_floats = num_floats + child_node.num_floats;
            }
        }

        self.common.num_floats = 1;
        self.floated_children = num_floats;

        self.box.map(|&box| {
            let style = box.style();
            do box.with_model |model| {
                model.compute_borders(style)
            }

            min_width = min_width.add(&box.get_min_width(ctx));
            pref_width = pref_width.add(&box.get_pref_width(ctx));
        });

        self.common.min_width = min_width;
        self.common.pref_width = pref_width;
    }

    pub fn assign_widths_float(@mut self) {
        debug!("assign_widths_float: assigning width for flow %?",  self.common.id);
        // position.size.width is set by parent even though we don't know
        // position.origin yet.
        let mut remaining_width = self.common.position.size.width;
        self.containing_width = remaining_width;
        let mut x_offset = Au(0);

        // Parent usually sets this, but floats are never inorder
        self.common.is_inorder = false;

        for &box in self.box.iter() {
            let style = box.style();
            do box.with_model |model| {
                // Can compute padding here since we know containing block width.
                model.compute_padding(style, remaining_width);

                // Margins for floats are 0 if auto.
                let margin_top = MaybeAuto::from_margin(style.margin_top(),
                                                        remaining_width,
                                                        style.font_size()).specified_or_zero();
                let margin_bottom = MaybeAuto::from_margin(style.margin_bottom(),
                                                           remaining_width,
                                                           style.font_size()).specified_or_zero();
                let margin_left = MaybeAuto::from_margin(style.margin_left(),
                                                         remaining_width,
                                                         style.font_size()).specified_or_zero();
                let margin_right = MaybeAuto::from_margin(style.margin_right(),
                                                          remaining_width,
                                                          style.font_size()).specified_or_zero();

                let shrink_to_fit = geometry::min(self.common.pref_width,
                                                  geometry::max(self.common.min_width,
                                                                remaining_width));

                let width = MaybeAuto::from_width(style.width(),
                                                  remaining_width,
                                                  style.font_size()).specified_or_default(shrink_to_fit);
                debug!("assign_widths_float -- width: %?", width);

                model.margin.top = margin_top;
                model.margin.right = margin_right;
                model.margin.bottom = margin_bottom;
                model.margin.left = margin_left;

                x_offset = model.offset();
                remaining_width = width;
            }

            do box.with_mut_base |base| {
                //The associated box is the border box of this flow
                base.position.origin.x = base.model.margin.left;

                let pb = base.model.padding.left + base.model.padding.right +
                    base.model.border.left + base.model.border.right;
                base.position.size.width = remaining_width + pb;
            }
        }

        self.common.position.size.width = remaining_width;

        let has_inorder_children = self.common.num_floats > 0;
        for kid in FloatFlow(self).children() {
            //assert!(kid.starts_block_flow() || kid.starts_inline_flow());

            do kid.with_mut_base |child_node| {
                child_node.position.origin.x = x_offset;
                child_node.position.size.width = remaining_width;
                child_node.is_inorder = has_inorder_children;

                if !child_node.is_inorder {
                    child_node.floats_in = FloatContext::new(0);
                }
            }
        }
    }

    pub fn assign_height_inorder_float(@mut self) {
        debug!("assign_height_inorder_float: assigning height for float %?", self.common.id);
        // assign_height_float was already called by the traversal function
        // so this is well-defined

        let mut height = Au(0);
        let mut clearance = Au(0);
        let mut full_noncontent_width = Au(0);
        let mut margin_height = Au(0);

        self.box.map(|&box| {
            height = do box.with_base |base| {
                base.position.size.height
            };
            clearance = match box.clear() {
                None => Au(0),
                Some(clear) => {
                    self.common.floats_in.clearance(clear)
                }
            };

            do box.with_base |base| {
                let noncontent_width = base.model.padding.left + base.model.padding.right +
                    base.model.border.left + base.model.border.right;

                full_noncontent_width = noncontent_width + base.model.margin.left + base.model.margin.right;
                margin_height = base.model.margin.top + base.model.margin.bottom;
            }

        });

        let info = PlacementInfo {
            width: self.common.position.size.width + full_noncontent_width,
            height: height + margin_height,
            ceiling: clearance,
            max_width: self.containing_width,
            f_type: self.float_type,
        };

        // Place the float and return the FloatContext back to the parent flow.
        // After, grab the position and use that to set our position.
        self.common.floats_out = self.common.floats_in.add_float(&info);
        self.rel_pos = self.common.floats_out.last_float_pos();
    }

    pub fn assign_height_float(@mut self, ctx: &mut LayoutContext) {
        debug!("assign_height_float: assigning height for float %?", self.common.id);
        let has_inorder_children = self.common.num_floats > 0;
        if has_inorder_children {
            let mut float_ctx = FloatContext::new(self.floated_children);
            for kid in FloatFlow(self).children() {
                do kid.with_mut_base |child_node| {
                    child_node.floats_in = float_ctx.clone();
                }
                kid.assign_height_inorder(ctx);
                do kid.with_mut_base |child_node| {
                    float_ctx = child_node.floats_out.clone();
                }
            }
        }

        let mut cur_y = Au(0);
        let mut top_offset = Au(0);

        for &box in self.box.iter() {
            do box.with_model |model| {
                top_offset = model.margin.top + model.border.top + model.padding.top;
                cur_y = cur_y + top_offset;
            }
        }

        for kid in FloatFlow(self).children() {
            do kid.with_mut_base |child_node| {
                child_node.position.origin.y = cur_y;
                cur_y = cur_y + child_node.position.size.height;
            };
        }

        let mut height = cur_y - top_offset;

        let mut noncontent_width = Au(0);
        let mut noncontent_height = Au(0);
        self.box.map(|&box| {
            do box.with_mut_base |base| {
                //The associated box is the border box of this flow
                base.position.origin.y = base.model.margin.top;

                noncontent_width = base.model.padding.left + base.model.padding.right +
                    base.model.border.left + base.model.border.right;
                noncontent_height = base.model.padding.top + base.model.padding.bottom +
                    base.model.border.top + base.model.border.bottom;
                base.position.size.height = height + noncontent_height;

            }
        });

        //TODO(eatkinson): compute heights properly using the 'height' property.
        for &box in self.box.iter() {
            let height_prop =
                MaybeAuto::from_height(box.style().height(),
                                       Au(0),
                                       box.style().font_size()).specified_or_zero();

            height = geometry::max(height, height_prop) + noncontent_height;
            debug!("assign_height_float -- height: %?", height);
            do box.with_mut_base |base| {
                base.position.size.height = height;
            }
        }
    }

    pub fn build_display_list_float<E:ExtraDisplayListData>(@mut self,
                                                            builder: &DisplayListBuilder,
                                                            dirty: &Rect<Au>,
                                                            list: &Cell<DisplayList<E>>)
                                                            -> bool {

        let abs_rect = Rect(self.common.abs_position, self.common.position.size);
        if !abs_rect.intersects(dirty) {
            return false;
        }

        let offset = self.common.abs_position + self.rel_pos;
        // add box that starts block context
        self.box.map(|&box| {
            box.build_display_list(builder, dirty, &offset, list)
        });

        // TODO: handle any out-of-flow elements

        // go deeper into the flow tree
        let flow = FloatFlow(self);
        for child in flow.children() {
            do child.with_mut_base |base| {
                base.abs_position = offset + base.position.origin;
            }
        }

        true
    }
}

<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate protobuf;
extern crate util;
extern crate rustc_serialize;
extern crate rlp;
#[macro_use]
extern crate serde_derive;
extern crate cita_crypto as crypto;
extern crate ethcore_logger;
#[macro_use]
extern crate log as rlog;

pub mod blockchain;
pub mod communication;
pub mod request;
pub mod into;
pub mod auth;

pub use auth::*;
use blockchain::*;
use communication::*;
use crypto::{PrivKey, PubKey, Signature, KeyPair, SIGNATURE_BYTES_LEN, Message as SignMessage, CreateKey, Sign};
use protobuf::Message;
use protobuf::core::parse_from_bytes;
pub use request::*;
use rlp::*;
use rustc_serialize::hex::ToHex;
use std::ops::Deref;
use std::result::Result::Err;
use util::{H256, Hashable, merklehash};
use util::snappy;

#[derive(Serialize, Deserialize, PartialEq)]
pub struct State(pub Vec<Vec<u8>>);

pub type TopicMessage = (String, communication::Message);

pub mod submodules {
    pub const JSON_RPC: u32 = 1;
    pub const NET: u32 = 2;
    pub const CHAIN: u32 = 3;
    pub const CONSENSUS: u32 = 4;
    pub const CONSENSUS_CMD: u32 = 5;
    pub const AUTH: u32 = 6;
}

pub mod topics {
    pub const DEFAULT: u16 = 0;
    pub const REQUEST: u16 = 1;
    pub const NEW_BLK: u16 = 2;
    pub const NEW_STATUS: u16 = 3;
    pub const SYNC_BLK: u16 = 4;
    pub const RESPONSE: u16 = 5;
    pub const NEW_TX: u16 = 6;
    pub const TX_RESPONSE: u16 = 7;
    pub const CONSENSUS_MSG: u16 = 8;
    pub const NEW_PROPOSAL: u16 = 9;
    pub const VERIFY_REQ: u16 = 10;
    pub const VERIFY_RESP: u16 = 11;
}

#[derive(Debug)]
pub enum MsgClass {
    REQUEST(Request),
    RESPONSE(Response),
    HEADER(BlockHeader),
    BODY(BlockBody),
    BLOCK(Block),
    TX(UnverifiedTransaction),
    TXRESPONSE(TxResponse),
    STATUS(Status),
    VERIFYREQ(VerifyReq),
    VERIFYRESP(VerifyResp),
    MSG(Vec<u8>),
}

pub fn topic_to_string(top: u16) -> &'static str {
    match top {
        topics::DEFAULT => "default",
        topics::REQUEST => "request",
        topics::NEW_BLK => "new_blk",
        topics::NEW_STATUS => "new_status",
        topics::SYNC_BLK => "sync_blk",
        topics::RESPONSE => "response",
        topics::NEW_TX => "new_tx",
        topics::TX_RESPONSE => "tx_response",
        topics::CONSENSUS_MSG => "consensus_msg",
        topics::NEW_PROPOSAL => "new_proposal",
        topics::VERIFY_REQ => "verify_req",
        topics::VERIFY_RESP => "verify_resp",
        _ => "",
    }
}

pub fn id_to_key(id: u32) -> &'static str {
    match id {
        submodules::JSON_RPC => "json_rpc",
        submodules::NET => "net",
        submodules::CHAIN => "chain",
        submodules::CONSENSUS => "consensus",
        submodules::CONSENSUS_CMD => "consensus_cmd",
        submodules::AUTH => "auth",
        _ => "",
    }
}

pub fn key_to_id(key: &str) -> u32 {
    if key.starts_with("jsonrpc") {
        submodules::JSON_RPC
    } else if key.starts_with("net") {
        submodules::NET
    } else if key.starts_with("chain") {
        submodules::CHAIN
    } else if key.starts_with("consensus_cmd") {
        submodules::CONSENSUS_CMD
    } else if key.starts_with("consensus") {
        submodules::CONSENSUS
    } else if key.starts_with("auth") {
        submodules::AUTH
    } else {
        0
    }
}

pub fn de_cmd_id(cmd_id: u32) -> (u32, u16) {
    let mut submodule = cmd_id >> 16;
    let sub = submodule;
    submodule = submodule << 16;
    let topic = (cmd_id - submodule) as u16;
    (sub, topic)
}

pub fn display_cmd(cmd_id: u32) -> (&'static str, &'static str) {
    let cd = de_cmd_id(cmd_id);
    (id_to_key(cd.0), topic_to_string(cd.1))
}

pub fn cmd_id(submodule: u32, topic: u16) -> u32 {
    (submodule << 16) + topic as u32
}

pub mod factory {
    use super::*;
    pub const ZERO_ORIGIN: u32 = 99999;

    pub fn create_msg(sub: u32, top: u16, msg_type: MsgType, content: Vec<u8>) -> communication::Message {
        let mut msg = communication::Message::new();
        msg.set_cmd_id(cmd_id(sub, top));
        msg.set_field_type(msg_type);
        msg.set_operate(communication::OperateType::BROADCAST);
        msg.set_origin(ZERO_ORIGIN);
        //compress data
        msg.set_content(snappy::cita_compresse(content));
        msg
    }

    ///for crate_msg extral version
    pub fn create_msg_ex(sub: u32, top: u16, msg_type: MsgType, operate: communication::OperateType, origin: u32, content: Vec<u8>) -> communication::Message {
        let mut msg = factory::create_msg(sub, top, msg_type, content);
        msg.set_origin(origin);
        msg.set_operate(operate);
        msg
    }
}

type CmdId = u32;
type Origin = u32;

pub fn parse_msg(msg: &[u8]) -> (CmdId, Origin, MsgClass) {
    let mut msg = parse_from_bytes::<communication::Message>(msg.as_ref()).unwrap();
    let content_msg = msg.take_content();
    let content_msg = snappy::cita_decompress(content_msg);
    let msg_class = match msg.get_field_type() {
        MsgType::REQUEST => MsgClass::REQUEST(parse_from_bytes::<Request>(&content_msg).unwrap()),
        MsgType::RESPONSE => {
            MsgClass::RESPONSE(parse_from_bytes::<Response>(&content_msg).unwrap())
        }
        MsgType::TX_RESPONSE => {
            MsgClass::TXRESPONSE(parse_from_bytes::<TxResponse>(&content_msg).unwrap())
        }
        MsgType::HEADER => MsgClass::HEADER(parse_from_bytes::<BlockHeader>(&content_msg).unwrap()),
        MsgType::BODY => MsgClass::BODY(parse_from_bytes::<BlockBody>(&content_msg).unwrap()),
        MsgType::BLOCK => MsgClass::BLOCK(parse_from_bytes::<Block>(&content_msg).unwrap()),
        MsgType::TX => MsgClass::TX(parse_from_bytes::<UnverifiedTransaction>(&content_msg).unwrap()),
        MsgType::STATUS => MsgClass::STATUS(parse_from_bytes::<Status>(&content_msg).unwrap()),
        MsgType::VERIFY_REQ => MsgClass::VERIFYREQ(parse_from_bytes::<VerifyReq>(&content_msg).unwrap()),
        MsgType::VERIFY_RESP => MsgClass::VERIFYRESP(parse_from_bytes::<VerifyResp>(&content_msg).unwrap()),
        MsgType::MSG => {
            let mut content = Vec::new();
            content.extend_from_slice(&content_msg);
            MsgClass::MSG(content)
        }
    };

    (msg.get_cmd_id(), msg.get_origin(), msg_class)
}

impl blockchain::Transaction {
    /// Signs the transaction by PrivKey.
    pub fn sign(&self, sk: PrivKey) -> SignedTransaction {
        let keypair = KeyPair::from_privkey(sk).unwrap();
        let pubkey = keypair.pubkey();
        let unverified_tx = self.build_unverified(sk);

        // Build SignedTransaction
        let mut signed_tx = SignedTransaction::new();
        signed_tx.set_signer(pubkey.to_vec());
        let bytes = unverified_tx.write_to_bytes().unwrap();
        signed_tx.set_tx_hash(bytes.crypt_hash().to_vec());
        signed_tx.set_transaction_with_sig(unverified_tx);
        signed_tx
    }

    /// Build UnverifiedTransaction
    pub fn build_unverified(&self, sk: PrivKey) -> UnverifiedTransaction {
        let mut unverified_tx = UnverifiedTransaction::new();
        let bytes = self.write_to_bytes().unwrap();
        let hash = bytes.crypt_hash();
        unverified_tx.set_transaction(self.clone());
        let signature = Signature::sign(&sk, &SignMessage::from(hash)).unwrap();
        unverified_tx.set_signature(signature.to_vec());
        unverified_tx.set_crypto(Crypto::SECP);
        unverified_tx
    }
}

impl blockchain::UnverifiedTransaction {
    /// Try to recover the public key.
    pub fn recover_public(&self) -> Result<(PubKey, H256), (H256, String)> {
        let bytes = self.get_transaction().write_to_bytes().unwrap();
        let hash = bytes.crypt_hash();
        let tx_hash = self.crypt_hash();
        if self.get_signature().len() != SIGNATURE_BYTES_LEN {
            trace!("Invalid signature length {}", hash);
            Err((hash, String::from("Invalid signature length")))
        } else {
            match self.get_crypto() {
                Crypto::SECP => {
                    let signature = Signature::from(self.get_signature());
                    match signature.recover(&hash) {
                        Ok(pubkey) => {
                            Ok((pubkey, tx_hash))
                        }
                        _ => {
                            trace!("Recover error {}", tx_hash);
                            Err((tx_hash, String::from("Recover error")))
                        }
                    }
                }
                _ => {
                    trace!("Unexpected crypto {}", tx_hash);
                    Err((tx_hash, String::from("Unexpected crypto")))
                }
            }
        }
    }

    pub fn crypt_hash(&self) -> H256 {
        let bytes = self.write_to_bytes().unwrap();
        bytes.crypt_hash()
    }
}

impl Deref for SignedTransaction {
    type Target = UnverifiedTransaction;

    fn deref(&self) -> &Self::Target {
        &self.get_transaction_with_sig()
    }
}

impl blockchain::SignedTransaction {
    /// Try to verify transaction and recover sender.
    pub fn verify_transaction(transaction: UnverifiedTransaction) -> Result<Self, H256> {
        let (public, tx_hash) = transaction.recover_public().map_err(|(hash, _)| hash)?;
        let mut signed_tx = SignedTransaction::new();
        signed_tx.set_signer(public.to_vec());
        signed_tx.set_tx_hash(tx_hash.to_vec());
        signed_tx.set_transaction_with_sig(transaction);
        Ok(signed_tx)
    }

    pub fn crypt_hash(&self) -> H256 {
        H256::from(self.tx_hash.as_slice())
    }
}

impl Eq for Proof {}

impl Decodable for Proof {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        rlp.decoder().decode_value(|bytes| Ok(parse_from_bytes::<Proof>(&bytes).unwrap()))
    }
}

impl Encodable for Proof {
    fn rlp_append(&self, s: &mut RlpStream) {
        s.encoder().encode_value(&self.write_to_bytes().unwrap());
    }
}

impl Block {
    pub fn crypt_hash(&self) -> H256 {
        self.get_header().crypt_hash()
    }

    pub fn crypt_hash_hex(&self) -> String {
        self.get_header().crypt_hash_hex()
    }
}

impl BlockHeader {
    pub fn crypt_hash(&self) -> H256 {
        let bytes = self.write_to_bytes().unwrap();
        bytes.crypt_hash()
    }

    pub fn crypt_hash_hex(&self) -> String {
        let bytes = self.write_to_bytes().unwrap();
        bytes.crypt_hash().to_hex()
    }
}

impl BlockBody {
    pub fn transaction_hashes(&self) -> Vec<H256> {
        self.get_transactions().iter().map(|ts| H256::from_slice(ts.get_tx_hash())).collect()
    }

    pub fn transactions_root(&self) -> H256 {
        merklehash::complete_merkle_root_raw(self.transaction_hashes().clone())
    }
}

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

    #[test]
    fn cmd_id_works() {
        assert_eq!(cmd_id(submodules::JSON_RPC, topics::NEW_TX), 0x10006);
        assert_eq!(cmd_id(submodules::CHAIN, topics::NEW_TX), 0x30006);
    }

    #[test]
    fn create_tx() {
        let keypair = KeyPair::gen_keypair();
        let pv = keypair.privkey();

        let data = vec![1];
        let mut tx = Transaction::new();
        tx.set_data(data);
        tx.set_nonce("0".to_string());
        tx.set_to("123".to_string());
        tx.set_valid_until_block(99999);
        tx.set_quota(999999999);

        let signed_tx = tx.sign(*pv);
        assert_eq!(signed_tx.crypt_hash(), signed_tx.get_transaction_with_sig().crypt_hash());
    }
}
<commit_msg>Fixed UnverifiedTransaction recover (#64)<commit_after>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate protobuf;
extern crate util;
extern crate rustc_serialize;
extern crate rlp;
#[macro_use]
extern crate serde_derive;
extern crate cita_crypto as crypto;
extern crate ethcore_logger;
#[macro_use]
extern crate log as rlog;

pub mod blockchain;
pub mod communication;
pub mod request;
pub mod into;
pub mod auth;

pub use auth::*;
use blockchain::*;
use communication::*;
use crypto::{PrivKey, PubKey, Signature, KeyPair, SIGNATURE_BYTES_LEN, Message as SignMessage, CreateKey, Sign};
use protobuf::Message;
use protobuf::core::parse_from_bytes;
pub use request::*;
use rlp::*;
use rustc_serialize::hex::ToHex;
use std::ops::Deref;
use std::result::Result::Err;
use util::{H256, Hashable, merklehash};
use util::snappy;

#[derive(Serialize, Deserialize, PartialEq)]
pub struct State(pub Vec<Vec<u8>>);

pub type TopicMessage = (String, communication::Message);

pub mod submodules {
    pub const JSON_RPC: u32 = 1;
    pub const NET: u32 = 2;
    pub const CHAIN: u32 = 3;
    pub const CONSENSUS: u32 = 4;
    pub const CONSENSUS_CMD: u32 = 5;
    pub const AUTH: u32 = 6;
}

pub mod topics {
    pub const DEFAULT: u16 = 0;
    pub const REQUEST: u16 = 1;
    pub const NEW_BLK: u16 = 2;
    pub const NEW_STATUS: u16 = 3;
    pub const SYNC_BLK: u16 = 4;
    pub const RESPONSE: u16 = 5;
    pub const NEW_TX: u16 = 6;
    pub const TX_RESPONSE: u16 = 7;
    pub const CONSENSUS_MSG: u16 = 8;
    pub const NEW_PROPOSAL: u16 = 9;
    pub const VERIFY_REQ: u16 = 10;
    pub const VERIFY_RESP: u16 = 11;
}

#[derive(Debug)]
pub enum MsgClass {
    REQUEST(Request),
    RESPONSE(Response),
    HEADER(BlockHeader),
    BODY(BlockBody),
    BLOCK(Block),
    TX(UnverifiedTransaction),
    TXRESPONSE(TxResponse),
    STATUS(Status),
    VERIFYREQ(VerifyReq),
    VERIFYRESP(VerifyResp),
    MSG(Vec<u8>),
}

pub fn topic_to_string(top: u16) -> &'static str {
    match top {
        topics::DEFAULT => "default",
        topics::REQUEST => "request",
        topics::NEW_BLK => "new_blk",
        topics::NEW_STATUS => "new_status",
        topics::SYNC_BLK => "sync_blk",
        topics::RESPONSE => "response",
        topics::NEW_TX => "new_tx",
        topics::TX_RESPONSE => "tx_response",
        topics::CONSENSUS_MSG => "consensus_msg",
        topics::NEW_PROPOSAL => "new_proposal",
        topics::VERIFY_REQ => "verify_req",
        topics::VERIFY_RESP => "verify_resp",
        _ => "",
    }
}

pub fn id_to_key(id: u32) -> &'static str {
    match id {
        submodules::JSON_RPC => "json_rpc",
        submodules::NET => "net",
        submodules::CHAIN => "chain",
        submodules::CONSENSUS => "consensus",
        submodules::CONSENSUS_CMD => "consensus_cmd",
        submodules::AUTH => "auth",
        _ => "",
    }
}

pub fn key_to_id(key: &str) -> u32 {
    if key.starts_with("jsonrpc") {
        submodules::JSON_RPC
    } else if key.starts_with("net") {
        submodules::NET
    } else if key.starts_with("chain") {
        submodules::CHAIN
    } else if key.starts_with("consensus_cmd") {
        submodules::CONSENSUS_CMD
    } else if key.starts_with("consensus") {
        submodules::CONSENSUS
    } else if key.starts_with("auth") {
        submodules::AUTH
    } else {
        0
    }
}

pub fn de_cmd_id(cmd_id: u32) -> (u32, u16) {
    let mut submodule = cmd_id >> 16;
    let sub = submodule;
    submodule = submodule << 16;
    let topic = (cmd_id - submodule) as u16;
    (sub, topic)
}

pub fn display_cmd(cmd_id: u32) -> (&'static str, &'static str) {
    let cd = de_cmd_id(cmd_id);
    (id_to_key(cd.0), topic_to_string(cd.1))
}

pub fn cmd_id(submodule: u32, topic: u16) -> u32 {
    (submodule << 16) + topic as u32
}

pub mod factory {
    use super::*;
    pub const ZERO_ORIGIN: u32 = 99999;

    pub fn create_msg(sub: u32, top: u16, msg_type: MsgType, content: Vec<u8>) -> communication::Message {
        let mut msg = communication::Message::new();
        msg.set_cmd_id(cmd_id(sub, top));
        msg.set_field_type(msg_type);
        msg.set_operate(communication::OperateType::BROADCAST);
        msg.set_origin(ZERO_ORIGIN);
        //compress data
        msg.set_content(snappy::cita_compresse(content));
        msg
    }

    ///for crate_msg extral version
    pub fn create_msg_ex(sub: u32, top: u16, msg_type: MsgType, operate: communication::OperateType, origin: u32, content: Vec<u8>) -> communication::Message {
        let mut msg = factory::create_msg(sub, top, msg_type, content);
        msg.set_origin(origin);
        msg.set_operate(operate);
        msg
    }
}

type CmdId = u32;
type Origin = u32;

pub fn parse_msg(msg: &[u8]) -> (CmdId, Origin, MsgClass) {
    let mut msg = parse_from_bytes::<communication::Message>(msg.as_ref()).unwrap();
    let content_msg = msg.take_content();
    let content_msg = snappy::cita_decompress(content_msg);
    let msg_class = match msg.get_field_type() {
        MsgType::REQUEST => MsgClass::REQUEST(parse_from_bytes::<Request>(&content_msg).unwrap()),
        MsgType::RESPONSE => {
            MsgClass::RESPONSE(parse_from_bytes::<Response>(&content_msg).unwrap())
        }
        MsgType::TX_RESPONSE => {
            MsgClass::TXRESPONSE(parse_from_bytes::<TxResponse>(&content_msg).unwrap())
        }
        MsgType::HEADER => MsgClass::HEADER(parse_from_bytes::<BlockHeader>(&content_msg).unwrap()),
        MsgType::BODY => MsgClass::BODY(parse_from_bytes::<BlockBody>(&content_msg).unwrap()),
        MsgType::BLOCK => MsgClass::BLOCK(parse_from_bytes::<Block>(&content_msg).unwrap()),
        MsgType::TX => MsgClass::TX(parse_from_bytes::<UnverifiedTransaction>(&content_msg).unwrap()),
        MsgType::STATUS => MsgClass::STATUS(parse_from_bytes::<Status>(&content_msg).unwrap()),
        MsgType::VERIFY_REQ => MsgClass::VERIFYREQ(parse_from_bytes::<VerifyReq>(&content_msg).unwrap()),
        MsgType::VERIFY_RESP => MsgClass::VERIFYRESP(parse_from_bytes::<VerifyResp>(&content_msg).unwrap()),
        MsgType::MSG => {
            let mut content = Vec::new();
            content.extend_from_slice(&content_msg);
            MsgClass::MSG(content)
        }
    };

    (msg.get_cmd_id(), msg.get_origin(), msg_class)
}

impl blockchain::Transaction {
    /// Signs the transaction by PrivKey.
    pub fn sign(&self, sk: PrivKey) -> SignedTransaction {
        let keypair = KeyPair::from_privkey(sk).unwrap();
        let pubkey = keypair.pubkey();
        let unverified_tx = self.build_unverified(sk);

        // Build SignedTransaction
        let mut signed_tx = SignedTransaction::new();
        signed_tx.set_signer(pubkey.to_vec());
        let bytes = unverified_tx.write_to_bytes().unwrap();
        signed_tx.set_tx_hash(bytes.crypt_hash().to_vec());
        signed_tx.set_transaction_with_sig(unverified_tx);
        signed_tx
    }

    /// Build UnverifiedTransaction
    pub fn build_unverified(&self, sk: PrivKey) -> UnverifiedTransaction {
        let mut unverified_tx = UnverifiedTransaction::new();
        let bytes = self.write_to_bytes().unwrap();
        let hash = bytes.crypt_hash();
        unverified_tx.set_transaction(self.clone());
        let signature = Signature::sign(&sk, &SignMessage::from(hash)).unwrap();
        unverified_tx.set_signature(signature.to_vec());
        unverified_tx.set_crypto(Crypto::SECP);
        unverified_tx
    }
}

impl blockchain::UnverifiedTransaction {
    /// Try to recover the public key.
    pub fn recover_public(&self) -> Result<(PubKey, H256), (H256, String)> {
        let bytes = self.get_transaction().write_to_bytes().unwrap();
        let hash = bytes.crypt_hash();
        let tx_hash = self.crypt_hash();
        if self.get_signature().len() != SIGNATURE_BYTES_LEN {
            trace!("Invalid signature length {}", hash);
            Err((tx_hash, String::from("Invalid signature length")))
        } else {
            match self.get_crypto() {
                Crypto::SECP => {
                    let signature = Signature::from(self.get_signature());
                    match signature.recover(&hash) {
                        Ok(pubkey) => {
                            Ok((pubkey, tx_hash))
                        }
                        _ => {
                            trace!("Recover error {}", tx_hash);
                            Err((tx_hash, String::from("Recover error")))
                        }
                    }
                }
                _ => {
                    trace!("Unexpected crypto {}", tx_hash);
                    Err((tx_hash, String::from("Unexpected crypto")))
                }
            }
        }
    }

    pub fn crypt_hash(&self) -> H256 {
        let bytes = self.write_to_bytes().unwrap();
        bytes.crypt_hash()
    }
}

impl Deref for SignedTransaction {
    type Target = UnverifiedTransaction;

    fn deref(&self) -> &Self::Target {
        &self.get_transaction_with_sig()
    }
}

impl blockchain::SignedTransaction {
    /// Try to verify transaction and recover sender.
    pub fn verify_transaction(transaction: UnverifiedTransaction) -> Result<Self, H256> {
        let (public, tx_hash) = transaction.recover_public().map_err(|(hash, _)| hash)?;
        let mut signed_tx = SignedTransaction::new();
        signed_tx.set_signer(public.to_vec());
        signed_tx.set_tx_hash(tx_hash.to_vec());
        signed_tx.set_transaction_with_sig(transaction);
        Ok(signed_tx)
    }

    pub fn crypt_hash(&self) -> H256 {
        H256::from(self.tx_hash.as_slice())
    }
}

impl Eq for Proof {}

impl Decodable for Proof {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        rlp.decoder().decode_value(|bytes| Ok(parse_from_bytes::<Proof>(&bytes).unwrap()))
    }
}

impl Encodable for Proof {
    fn rlp_append(&self, s: &mut RlpStream) {
        s.encoder().encode_value(&self.write_to_bytes().unwrap());
    }
}

impl Block {
    pub fn crypt_hash(&self) -> H256 {
        self.get_header().crypt_hash()
    }

    pub fn crypt_hash_hex(&self) -> String {
        self.get_header().crypt_hash_hex()
    }
}

impl BlockHeader {
    pub fn crypt_hash(&self) -> H256 {
        let bytes = self.write_to_bytes().unwrap();
        bytes.crypt_hash()
    }

    pub fn crypt_hash_hex(&self) -> String {
        let bytes = self.write_to_bytes().unwrap();
        bytes.crypt_hash().to_hex()
    }
}

impl BlockBody {
    pub fn transaction_hashes(&self) -> Vec<H256> {
        self.get_transactions().iter().map(|ts| H256::from_slice(ts.get_tx_hash())).collect()
    }

    pub fn transactions_root(&self) -> H256 {
        merklehash::complete_merkle_root_raw(self.transaction_hashes().clone())
    }
}

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

    #[test]
    fn cmd_id_works() {
        assert_eq!(cmd_id(submodules::JSON_RPC, topics::NEW_TX), 0x10006);
        assert_eq!(cmd_id(submodules::CHAIN, topics::NEW_TX), 0x30006);
    }

    #[test]
    fn create_tx() {
        let keypair = KeyPair::gen_keypair();
        let pv = keypair.privkey();

        let data = vec![1];
        let mut tx = Transaction::new();
        tx.set_data(data);
        tx.set_nonce("0".to_string());
        tx.set_to("123".to_string());
        tx.set_valid_until_block(99999);
        tx.set_quota(999999999);

        let signed_tx = tx.sign(*pv);
        assert_eq!(signed_tx.crypt_hash(), signed_tx.get_transaction_with_sig().crypt_hash());
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::collections::HashMap;

fn main() {
    let mut letters = HashMap::<char, i32>::new();
    let mut sum = 0;

    let stdin = io::stdin();
    let stdin = stdin.lock().lines();
    for line in stdin {
        let line = line.unwrap();
        let line: Vec<&str> = line.split(|c| c == '[' || c == ']').collect();
        let name = line[0];
        let checksum = line[1];
        for c in name.chars().filter(|&c| c.is_alphabetic()) {
            *letters.entry(c).or_insert(0) += 1;
        }
        let mut letter_freq: Vec<(i32, char)> = letters.iter().map(|(&c, &n)| (-n, c)).collect();
        letter_freq.sort_by(|l1, l2| l1.cmp(l2));
        let real_checksum = letter_freq.into_iter().take(5).map(|(_, c)| c).collect::<String>();
        if real_checksum == checksum {
            let id: String = name.chars().filter(|&c| c.is_numeric()).collect();
            let id = id.parse::<u32>().unwrap();
            sum += id;
        }
        letters.clear();
    }
    println!("part1: {}", sum);
}
<commit_msg>rust day04 part2<commit_after>use std::io;
use std::io::prelude::*;
use std::collections::HashMap;

fn decode_name(name: &str) -> String {
    let id: String = name.chars().filter(|&c| c.is_numeric()).collect();
    let id = id.parse::<u32>().unwrap();
    let rotate = |c: char, n| ((c as u32 - 97 + n) % 26 + 97) as u8 as char;
    name.chars()
        .filter(|&c| !c.is_numeric())
        .map(|c| if c == '-' { ' ' } else { rotate(c, id) })
        .collect()
}

fn main() {
    let mut letters = HashMap::<char, i32>::new();
    let mut sum = 0;
    let stdin = io::stdin();
    let stdin = stdin.lock().lines();
    for line in stdin {
        let line = line.unwrap();
        let line: Vec<&str> = line.split(|c| c == '[' || c == ']').collect();
        let name = line[0];
        let checksum = line[1];
        for c in name.chars().filter(|&c| c.is_alphabetic()) {
            *letters.entry(c).or_insert(0) += 1;
        }
        let mut letter_freq: Vec<(i32, char)> = letters.iter().map(|(&c, &n)| (-n, c)).collect();
        letter_freq.sort_by(|l1, l2| l1.cmp(l2));
        let real_checksum = letter_freq.into_iter().take(5).map(|(_, c)| c).collect::<String>();
        if real_checksum == checksum {
            let id: String = name.chars().filter(|&c| c.is_numeric()).collect();
            let id = id.parse::<u32>().unwrap();
            sum += id;
            if decode_name(name) == "northpole object storage " {
                println!("part2: {}", id);
            }
        }
        letters.clear();
    }
    println!("part1: {}", sum);
}
<|endoftext|>