<commit_before>use node_test_rig::{
    environment::RuntimeContext,
    eth2::{types::StateId, BeaconNodeHttpClient},
    ClientConfig, LocalBeaconNode, LocalValidatorClient, ValidatorConfig, ValidatorFiles,
};
use parking_lot::RwLock;
use std::ops::Deref;
use std::sync::Arc;
use types::{Epoch, EthSpec};

const BOOTNODE_PORT: u16 = 42424;
pub const INVALID_ADDRESS: &str = "http://127.0.0.1:42423";

/// Helper struct to reduce `Arc` usage.
pub struct Inner<E: EthSpec> {
    pub context: RuntimeContext<E>,
    pub beacon_nodes: RwLock<Vec<LocalBeaconNode<E>>>,
    pub validator_clients: RwLock<Vec<LocalValidatorClient<E>>>,
}

/// Represents a set of interconnected `LocalBeaconNode` and `LocalValidatorClient`.
///
/// Provides functions to allow adding new beacon nodes and validators.
pub struct LocalNetwork<E: EthSpec> {
    inner: Arc<Inner<E>>,
}

impl<E: EthSpec> Clone for LocalNetwork<E> {
    fn clone(&self) -> Self {
        Self {
            inner: self.inner.clone(),
        }
    }
}

impl<E: EthSpec> Deref for LocalNetwork<E> {
    type Target = Inner<E>;

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

impl<E: EthSpec> LocalNetwork<E> {
    /// Creates a new network with a single `BeaconNode`.
    pub async fn new(
        context: RuntimeContext<E>,
        mut beacon_config: ClientConfig,
    ) -> Result<Self, String> {
        beacon_config.network.discovery_port = BOOTNODE_PORT;
        beacon_config.network.libp2p_port = BOOTNODE_PORT;
        beacon_config.network.enr_udp_port = Some(BOOTNODE_PORT);
        beacon_config.network.enr_tcp_port = Some(BOOTNODE_PORT);
        let beacon_node =
            LocalBeaconNode::production(context.service_context("boot_node".into()), beacon_config)
                .await?;
        Ok(Self {
            inner: Arc::new(Inner {
                context,
                beacon_nodes: RwLock::new(vec![beacon_node]),
                validator_clients: RwLock::new(vec![]),
            }),
        })
    }

    /// Returns the number of beacon nodes in the network.
    ///
    /// Note: does not count nodes that are external to this `LocalNetwork` that may have connected
    /// (e.g., another Lighthouse process on the same machine.)
    pub fn beacon_node_count(&self) -> usize {
        self.beacon_nodes.read().len()
    }

    /// Returns the number of validator clients in the network.
    ///
    /// Note: does not count nodes that are external to this `LocalNetwork` that may have connected
    /// (e.g., another Lighthouse process on the same machine.)
    pub fn validator_client_count(&self) -> usize {
        self.validator_clients.read().len()
    }

    /// Adds a beacon node to the network, connecting to the 0'th beacon node via ENR.
    pub async fn add_beacon_node(&self, mut beacon_config: ClientConfig) -> Result<(), String> {
        let self_1 = self.clone();
        println!("Adding beacon node..");
        {
            let read_lock = self.beacon_nodes.read();

            let boot_node = read_lock.first().expect("should have at least one node");

            beacon_config.network.boot_nodes_enr.push(
                boot_node
                    .client
                    .enr()
                    .expect("bootnode must have a network"),
            );
            let count = self.beacon_node_count() as u16;
            beacon_config.network.discovery_port = BOOTNODE_PORT + count;
            beacon_config.network.libp2p_port = BOOTNODE_PORT + count;
            beacon_config.network.enr_udp_port = Some(BOOTNODE_PORT + count);
            beacon_config.network.enr_tcp_port = Some(BOOTNODE_PORT + count);
        }

        let index = self.beacon_nodes.read().len();

        let beacon_node = LocalBeaconNode::production(
            self.context.service_context(format!("node_{}", index)),
            beacon_config,
        )
        .await?;
        self_1.beacon_nodes.write().push(beacon_node);
        Ok(())
    }

    /// Adds a validator client to the network, connecting it to the beacon node with index
    /// `beacon_node`.
    pub async fn add_validator_client(
        &self,
        mut validator_config: ValidatorConfig,
        beacon_node: usize,
        validator_files: ValidatorFiles,
        invalid_first_beacon_node: bool, //to test beacon node fallbacks
    ) -> Result<(), String> {
        let index = self.validator_clients.read().len();
        let context = self.context.service_context(format!("validator_{}", index));
        let self_1 = self.clone();
        let socket_addr = {
            let read_lock = self.beacon_nodes.read();
            let beacon_node = read_lock
                .get(beacon_node)
                .ok_or_else(|| format!("No beacon node for index {}", beacon_node))?;
            beacon_node
                .client
                .http_api_listen_addr()
                .expect("Must have http started")
        };

        let beacon_node = format!("http://{}:{}", socket_addr.ip(), socket_addr.port());
        validator_config.beacon_nodes = if invalid_first_beacon_node {
            vec![INVALID_ADDRESS.to_string(), beacon_node]
        } else {
            vec![beacon_node]
        };
        let validator_client = LocalValidatorClient::production_with_insecure_keypairs(
            context,
            validator_config,
            validator_files,
        )
        .await?;
        self_1.validator_clients.write().push(validator_client);
        Ok(())
    }

    /// For all beacon nodes in `Self`, return a HTTP client to access each nodes HTTP API.
    pub fn remote_nodes(&self) -> Result<Vec<BeaconNodeHttpClient>, String> {
        let beacon_nodes = self.beacon_nodes.read();

        beacon_nodes
            .iter()
            .map(|beacon_node| beacon_node.remote_node())
            .collect()
    }

    /// Return current epoch of bootnode.
    pub async fn bootnode_epoch(&self) -> Result<Epoch, String> {
        let nodes = self.remote_nodes().expect("Failed to get remote nodes");
        let bootnode = nodes.first().expect("Should contain bootnode");
        bootnode
            .get_beacon_states_finality_checkpoints(StateId::Head)
            .await
            .map_err(|e| format!("Cannot get head: {:?}", e))
            .map(|body| body.unwrap().data.finalized.epoch)
    }
}
<commit_msg>[simulator] Fix race condition when creating LocalBeaconNode (#2137)<commit_after>use node_test_rig::{
    environment::RuntimeContext,
    eth2::{types::StateId, BeaconNodeHttpClient},
    ClientConfig, LocalBeaconNode, LocalValidatorClient, ValidatorConfig, ValidatorFiles,
};
use parking_lot::RwLock;
use std::ops::Deref;
use std::sync::Arc;
use types::{Epoch, EthSpec};

const BOOTNODE_PORT: u16 = 42424;
pub const INVALID_ADDRESS: &str = "http://127.0.0.1:42423";

/// Helper struct to reduce `Arc` usage.
pub struct Inner<E: EthSpec> {
    pub context: RuntimeContext<E>,
    pub beacon_nodes: RwLock<Vec<LocalBeaconNode<E>>>,
    pub validator_clients: RwLock<Vec<LocalValidatorClient<E>>>,
}

/// Represents a set of interconnected `LocalBeaconNode` and `LocalValidatorClient`.
///
/// Provides functions to allow adding new beacon nodes and validators.
pub struct LocalNetwork<E: EthSpec> {
    inner: Arc<Inner<E>>,
}

impl<E: EthSpec> Clone for LocalNetwork<E> {
    fn clone(&self) -> Self {
        Self {
            inner: self.inner.clone(),
        }
    }
}

impl<E: EthSpec> Deref for LocalNetwork<E> {
    type Target = Inner<E>;

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

impl<E: EthSpec> LocalNetwork<E> {
    /// Creates a new network with a single `BeaconNode`.
    pub async fn new(
        context: RuntimeContext<E>,
        mut beacon_config: ClientConfig,
    ) -> Result<Self, String> {
        beacon_config.network.discovery_port = BOOTNODE_PORT;
        beacon_config.network.libp2p_port = BOOTNODE_PORT;
        beacon_config.network.enr_udp_port = Some(BOOTNODE_PORT);
        beacon_config.network.enr_tcp_port = Some(BOOTNODE_PORT);
        let beacon_node =
            LocalBeaconNode::production(context.service_context("boot_node".into()), beacon_config)
                .await?;
        Ok(Self {
            inner: Arc::new(Inner {
                context,
                beacon_nodes: RwLock::new(vec![beacon_node]),
                validator_clients: RwLock::new(vec![]),
            }),
        })
    }

    /// Returns the number of beacon nodes in the network.
    ///
    /// Note: does not count nodes that are external to this `LocalNetwork` that may have connected
    /// (e.g., another Lighthouse process on the same machine.)
    pub fn beacon_node_count(&self) -> usize {
        self.beacon_nodes.read().len()
    }

    /// Returns the number of validator clients in the network.
    ///
    /// Note: does not count nodes that are external to this `LocalNetwork` that may have connected
    /// (e.g., another Lighthouse process on the same machine.)
    pub fn validator_client_count(&self) -> usize {
        self.validator_clients.read().len()
    }

    /// Adds a beacon node to the network, connecting to the 0'th beacon node via ENR.
    pub async fn add_beacon_node(&self, mut beacon_config: ClientConfig) -> Result<(), String> {
        let self_1 = self.clone();
        println!("Adding beacon node..");
        {
            let read_lock = self.beacon_nodes.read();

            let boot_node = read_lock.first().expect("should have at least one node");

            beacon_config.network.boot_nodes_enr.push(
                boot_node
                    .client
                    .enr()
                    .expect("bootnode must have a network"),
            );
            let count = self.beacon_node_count() as u16;
            beacon_config.network.discovery_port = BOOTNODE_PORT + count;
            beacon_config.network.libp2p_port = BOOTNODE_PORT + count;
            beacon_config.network.enr_udp_port = Some(BOOTNODE_PORT + count);
            beacon_config.network.enr_tcp_port = Some(BOOTNODE_PORT + count);
        }

        let mut write_lock = self_1.beacon_nodes.write();
        let index = write_lock.len();

        let beacon_node = LocalBeaconNode::production(
            self.context.service_context(format!("node_{}", index)),
            beacon_config,
        )
        .await?;
        write_lock.push(beacon_node);
        Ok(())
    }

    /// Adds a validator client to the network, connecting it to the beacon node with index
    /// `beacon_node`.
    pub async fn add_validator_client(
        &self,
        mut validator_config: ValidatorConfig,
        beacon_node: usize,
        validator_files: ValidatorFiles,
        invalid_first_beacon_node: bool, //to test beacon node fallbacks
    ) -> Result<(), String> {
        let index = self.validator_clients.read().len();
        let context = self.context.service_context(format!("validator_{}", index));
        let self_1 = self.clone();
        let socket_addr = {
            let read_lock = self.beacon_nodes.read();
            let beacon_node = read_lock
                .get(beacon_node)
                .ok_or_else(|| format!("No beacon node for index {}", beacon_node))?;
            beacon_node
                .client
                .http_api_listen_addr()
                .expect("Must have http started")
        };

        let beacon_node = format!("http://{}:{}", socket_addr.ip(), socket_addr.port());
        validator_config.beacon_nodes = if invalid_first_beacon_node {
            vec![INVALID_ADDRESS.to_string(), beacon_node]
        } else {
            vec![beacon_node]
        };
        let validator_client = LocalValidatorClient::production_with_insecure_keypairs(
            context,
            validator_config,
            validator_files,
        )
        .await?;
        self_1.validator_clients.write().push(validator_client);
        Ok(())
    }

    /// For all beacon nodes in `Self`, return a HTTP client to access each nodes HTTP API.
    pub fn remote_nodes(&self) -> Result<Vec<BeaconNodeHttpClient>, String> {
        let beacon_nodes = self.beacon_nodes.read();

        beacon_nodes
            .iter()
            .map(|beacon_node| beacon_node.remote_node())
            .collect()
    }

    /// Return current epoch of bootnode.
    pub async fn bootnode_epoch(&self) -> Result<Epoch, String> {
        let nodes = self.remote_nodes().expect("Failed to get remote nodes");
        let bootnode = nodes.first().expect("Should contain bootnode");
        bootnode
            .get_beacon_states_finality_checkpoints(StateId::Head)
            .await
            .map_err(|e| format!("Cannot get head: {:?}", e))
            .map(|body| body.unwrap().data.finalized.epoch)
    }
}
<|endoftext|>


<commit_before>extern crate protobuf;
extern crate rand;
extern crate time;

use std::fs::File;
use std::path::Path;

use rand::Rng;
use rand::StdRng;
use rand::SeedableRng;

use protobuf::Message;
use perftest_data::PerftestData;

mod perftest_data;

fn measure_ns<R, F : FnMut() -> R>(mut f: F) -> (u64, R) {
    let start = time::precise_time_ns();
    let r = f();
    (time::precise_time_ns() - start, r)
}

fn measure_and_print<R, F : FnMut() -> R>(title: &str, iter: u64, f: F) -> R {
    let (ns, r) = measure_ns(f);
    let ns_per_iter = ns / iter;
    println!("{}: {} ns per iter", title, ns_per_iter);
    r
}

struct TestRunner {
    data_size: u32,
    selected: Option<String>,
    any_matched: bool,
}

impl TestRunner {
    fn run_test<M : Message + Clone + PartialEq>(&self, name: &str, data: &[M]) {
        assert!(data.len() > 0, "empty string for test: {}", name);

        let mut rng: StdRng = SeedableRng::from_seed([
            10, 20, 30, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
        ]);

        let mut random_data: Vec<M> = Vec::new();

        let mut total_size = 0;
        while total_size < self.data_size {
            let ref item = data[rng.gen_range(0, data.len())];
            random_data.push(item.clone());
            total_size += item.compute_size();
        }

        let mut buf = Vec::new();
        measure_and_print(&format!("{}: write", name), random_data.len() as u64, || {
            for m in &random_data {
                m.write_length_delimited_to_vec(&mut buf).unwrap();
            }
        });

        let read_data =
            measure_and_print(&format!("{}: read", name), random_data.len() as u64, || {
                let mut r = Vec::new();
                let mut coded_input_stream = protobuf::CodedInputStream::from_bytes(&buf);
                while !coded_input_stream.eof().unwrap() {
                    r.push(coded_input_stream.read_message().unwrap());
                }
                r
            });

        assert_eq!(random_data, read_data);

        let merged = measure_and_print(
            &format!("{}: read reuse", name),
            random_data.len() as u64,
            || {
                let mut coded_input_stream = protobuf::CodedInputStream::from_bytes(&buf);
                let mut msg: M = Message::new();
                let mut count = 0;
                while !coded_input_stream.eof().unwrap() {
                    msg.clear();
                    coded_input_stream.merge_message(&mut msg).unwrap();
                    count += 1;
                }
                count
            },
        );

        assert_eq!(random_data.len(), merged);
    }

    fn test<M : Message + Clone + PartialEq>(&mut self, name: &str, data: &[M]) {
        if self.selected.as_ref().map(|s| *s == name).unwrap_or(true) {
            self.run_test(name, data);
            self.any_matched = true;
        }
    }

    fn check(&self) {
        if !self.any_matched {
            let name = self.selected.as_ref().map(|s| &s[..]).unwrap_or("bug");
            panic!("no tests found with name {}", name);
        }
    }
}

fn main() {
    let args = std::env::args().collect::<Vec<_>>();
    if args.len() > 3 {
        panic!("usage: {} [data_size] [test]", args[0])
    }
    let data_size = args.iter()
        .nth(1)
        .map(|x| x.parse().unwrap())
        .unwrap_or(1000000);
    let selected = args.iter().nth(2).cloned();

    let mut runner = TestRunner {
        selected: selected,
        any_matched: false,
        data_size: data_size,
    };

    let mut is = File::open(&Path::new("perftest_data.pbbin")).unwrap();
    let test_data = protobuf::parse_from_reader::<PerftestData>(&mut is).unwrap();

    runner.test("test1", test_data.get_test1());
    runner.test("test_repeated_bool", test_data.get_test_repeated_bool());
    runner.test(
        "test_repeated_packed_int32",
        test_data.get_test_repeated_packed_int32(),
    );
    runner.test(
        "test_repeated_messages",
        test_data.get_test_repeated_messages(),
    );
    runner.test(
        "test_optional_messages",
        test_data.get_test_optional_messages(),
    );
    runner.test("test_strings", test_data.get_test_strings());
    runner.test(
        "test_small_bytearrays",
        test_data.get_test_small_bytearrays(),
    );
    runner.test(
        "test_large_bytearrays",
        test_data.get_test_large_bytearrays(),
    );
    runner.check();
}
<commit_msg>Fix perftest<commit_after>extern crate protobuf;
extern crate rand;
extern crate time;

use std::fs::File;
use std::path::Path;

use rand::Rng;
use rand::StdRng;
use rand::SeedableRng;

use protobuf::Message;
use perftest_data::PerftestData;

mod perftest_data;

fn measure_ns<R, F : FnMut() -> R>(mut f: F) -> (u64, R) {
    let start = time::precise_time_ns();
    let r = f();
    (time::precise_time_ns() - start, r)
}

fn measure_and_print<R, F : FnMut() -> R>(title: &str, iter: u64, f: F) -> R {
    let (ns, r) = measure_ns(f);
    let ns_per_iter = ns / iter;
    println!("{}: {} ns per iter", title, ns_per_iter);
    r
}

struct TestRunner {
    data_size: u32,
    selected: Option<String>,
    any_matched: bool,
}

impl TestRunner {
    fn run_test<M : Message + Clone + PartialEq>(&self, name: &str, data: &[M]) {
        assert!(data.len() > 0, "empty string for test: {}", name);

        let mut rng: StdRng = SeedableRng::from_seed([
            10, 20, 30, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
        ]);

        let mut random_data: Vec<M> = Vec::new();

        let mut total_size = 0;
        while total_size < self.data_size {
            let ref item = data[rng.gen_range(0, data.len())];
            random_data.push(item.clone());
            total_size += item.compute_size();
        }

        let mut buf = Vec::new();
        measure_and_print(&format!("{}: write", name), random_data.len() as u64, || {
            for m in &random_data {
                m.write_length_delimited_to_vec(&mut buf).unwrap();
            }
        });

        let read_data =
            measure_and_print(&format!("{}: read", name), random_data.len() as u64, || {
                let mut r = Vec::new();
                let mut coded_input_stream = protobuf::CodedInputStream::from_bytes(&buf);
                while !coded_input_stream.eof().unwrap() {
                    r.push(coded_input_stream.read_message().unwrap());
                }
                r
            });

        assert_eq!(random_data, read_data);

        let merged = measure_and_print(
            &format!("{}: read reuse", name),
            random_data.len() as u64,
            || {
                let mut coded_input_stream = protobuf::CodedInputStream::from_bytes(&buf);
                let mut msg: M = Message::new();
                let mut count = 0;
                while !coded_input_stream.eof().unwrap() {
                    msg.clear();
                    coded_input_stream.merge_message(&mut msg).unwrap();
                    count += 1;
                }
                count
            },
        );

        assert_eq!(random_data.len(), merged);
    }

    fn test<M : Message + Clone + PartialEq>(&mut self, name: &str, data: &[M]) {
        if self.selected.as_ref().map(|s| *s == name).unwrap_or(true) {
            self.run_test(name, data);
            self.any_matched = true;
        }
    }

    fn check(&self) {
        if !self.any_matched {
            let name = self.selected.as_ref().map(|s| &s[..]).unwrap_or("bug");
            panic!("no tests found with name {}", name);
        }
    }
}

fn main() {
    let args = std::env::args().collect::<Vec<_>>();
    if args.len() > 3 {
        panic!("usage: {} [data_size] [test]", args[0])
    }
    let data_size = args.iter()
        .nth(1)
        .map(|x| x.parse().unwrap())
        .unwrap_or(1000000);
    let selected = args.iter().nth(2).cloned();

    let mut runner = TestRunner {
        selected: selected,
        any_matched: false,
        data_size: data_size,
    };

    let mut is = File::open(&Path::new("perftest_data.pbbin")).unwrap();
    let test_data = protobuf::parse_from_reader::<PerftestData>(&mut is).unwrap();

    runner.test("test1", &test_data.test1);
    runner.test("test_repeated_bool", &test_data.test_repeated_bool);
    runner.test(
        "test_repeated_packed_int32",
        &test_data.test_repeated_packed_int32,
    );
    runner.test(
        "test_repeated_messages",
        &test_data.test_repeated_messages,
    );
    runner.test(
        "test_optional_messages",
        &test_data.test_optional_messages,
    );
    runner.test("test_strings", &test_data.test_strings);
    runner.test(
        "test_small_bytearrays",
        &test_data.test_small_bytearrays,
    );
    runner.test(
        "test_large_bytearrays",
        &test_data.test_large_bytearrays,
    );
    runner.check();
}
<|endoftext|>


<commit_before>/**
 * http://doc.rust-lang.org/guide-testing.html
 * http://doc.rust-lang.org/test/index.html
 * rustc unittests.rs --test -o unittests
 * ./unittests --test
 *
 * @license MIT license <http://www.opensource.org/licenses/mit-license.php>
 */
#[cfg(test)]
mod tests {
	#[test]
	#[should_fail]
	fn test_fail() {
		assert!(1i == 2i, "This test must fail!");
	}
	#[test]
	fn test_float() {
		let expected = 1f64;
		let mut actual = 1f64;
		let precision = 0.1f64;
		actual = actual + precision / 2f64;
		assert!((expected - actual).abs() < precision);
	}
	#[test]
	fn test_success() {
		assert!(1 == 1);
		assert_eq!(1i, 1i);
	}
}
#[cfg(not(test))]
fn main() {
	println!("This program must be build and run with --test");
}
<commit_msg>Changes to version rustc 0.12.0-pre-nightly (f5ac41185 2014-08-05 19:06:23 +0000)<commit_after>/**
 * http://doc.rust-lang.org/guide-testing.html
 * http://doc.rust-lang.org/test/index.html
 * rustc unittests.rs --test -o unittests
 * ./unittests --test
 *
 * @license MIT license <http://www.opensource.org/licenses/mit-license.php>
 */
#[cfg(test)]
mod tests {
	#[test]
	#[should_fail]
	fn test_fail() {
		assert!(1i == 2i, "This test must fail!");
	}
	#[test]
	fn test_float() {
		let expected = 1f64;
		let mut actual = 1f64;
		let precision = 0.1f64;
		actual = actual + precision / 2f64;
		assert!((expected - actual).abs() < precision);
	}
	#[test]
	fn test_success() {
		assert!(1i == 1i);
		assert_eq!(1i, 1i);
	}
}
#[cfg(not(test))]
fn main() {
	println!("This program must be build and run with --test");
}
<|endoftext|>


<commit_before>//@ignore-windows: Concurrency on Windows is not supported yet.
//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows

// The following tests check whether our weak memory emulation produces
// any inconsistent execution outcomes
//
// Due to the random nature of choosing valid stores, it is always
// possible that our tests spuriously succeeds: even though our weak
// memory emulation code has incorrectly identified a store in
// modification order as being valid, it may be never chosen by
// the RNG and never observed in our tests.
//
// To mitigate this, each test is ran enough times such that the chance
// of spurious success is very low. These tests never supriously fail.

// Test cases and their consistent outcomes are from
// http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/
// Based on
// M. Batty, S. Owens, S. Sarkar, P. Sewell and T. Weber,
// "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011.
// Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf.

use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::*;
use std::thread::spawn;

#[derive(Copy, Clone)]
struct EvilSend<T>(pub T);

unsafe impl<T> Send for EvilSend<T> {}
unsafe impl<T> Sync for EvilSend<T> {}

// We can't create static items because we need to run each test
// multiple times
fn static_atomic(val: usize) -> &'static AtomicUsize {
    let ret = Box::leak(Box::new(AtomicUsize::new(val)));
    ret
}

// Spins until it acquires a pre-determined value.
fn acquires_value(loc: &AtomicUsize, val: usize) -> usize {
    while loc.load(Acquire) != val {
        std::hint::spin_loop();
    }
    val
}

fn test_corr() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, Relaxed);
        x.store(2, Relaxed);
    });

    #[rustfmt::skip]
    let j2 = spawn(move || {
        let r2 = x.load(Relaxed); // -------------------------------------+
        y.store(1, Release); // ---------------------+                    |
        r2 //                                        |                    |
    }); //                                           |                    |
    #[rustfmt::skip] //                              |synchronizes-with   |happens-before
    let j3 = spawn(move || { //                      |                    |
        acquires_value(&y, 1); // <------------------+                    |
        x.load(Relaxed) // <----------------------------------------------+
        // The two reads on x are ordered by hb, so they cannot observe values
        // differently from the modification order. If the first read observed
        // 2, then the second read must observe 2 as well.
    });

    j1.join().unwrap();
    let r2 = j2.join().unwrap();
    let r3 = j3.join().unwrap();
    if r2 == 2 {
        assert_eq!(r3, 2);
    }
}

fn test_wrc() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    #[rustfmt::skip]
    let j1 = spawn(move || {
        x.store(1, Release); // ---------------------+---------------------+
    }); //                                           |                     |
    #[rustfmt::skip] //                              |synchronizes-with    |
    let j2 = spawn(move || { //                      |                     |
        acquires_value(&x, 1); // <------------------+                     |
        y.store(1, Release); // ---------------------+                     |happens-before
    }); //                                           |                     |
    #[rustfmt::skip] //                              |synchronizes-with    |
    let j3 = spawn(move || { //                      |                     |
        acquires_value(&y, 1); // <------------------+                     |
        x.load(Relaxed) // <-----------------------------------------------+
    });

    j1.join().unwrap();
    j2.join().unwrap();
    let r3 = j3.join().unwrap();

    assert_eq!(r3, 1);
}

fn test_message_passing() {
    let mut var = 0u32;
    let ptr = &mut var as *mut u32;
    let x = EvilSend(ptr);
    let y = static_atomic(0);

    #[rustfmt::skip]
    let j1 = spawn(move || {
        unsafe { *x.0 = 1 }; // -----------------------------------------+
        y.store(1, Release); // ---------------------+                   |
    }); //                                           |                   |
    #[rustfmt::skip] //                              |synchronizes-with  | happens-before
    let j2 = spawn(move || { //                      |                   |
        acquires_value(&y, 1); // <------------------+                   |
        unsafe { *x.0 } // <---------------------------------------------+
    });

    j1.join().unwrap();
    let r2 = j2.join().unwrap();

    assert_eq!(r2, 1);
}

// LB+acq_rel+acq_rel
fn test_load_buffering_acq_rel() {
    let x = static_atomic(0);
    let y = static_atomic(0);
    let j1 = spawn(move || {
        let r1 = x.load(Acquire);
        y.store(1, Release);
        r1
    });

    let j2 = spawn(move || {
        let r2 = y.load(Acquire);
        x.store(1, Release);
        r2
    });

    let r1 = j1.join().unwrap();
    let r2 = j2.join().unwrap();

    // 3 consistent outcomes: (0,0), (0,1), (1,0)
    assert_ne!((r1, r2), (1, 1));
}

fn test_mixed_access() {
    /*
    int main() {
      atomic_int x = 0;
      {{{
        x.store(1, mo_relaxed);
      }}}

      x.store(2, mo_relaxed);

      {{{
        r1 = x.load(mo_relaxed);
      }}}

      return 0;
    }
        */
    let x = static_atomic(0);

    spawn(move || {
        x.store(1, Relaxed);
    })
    .join()
    .unwrap();

    x.store(2, Relaxed);

    let r2 = spawn(move || x.load(Relaxed)).join().unwrap();

    assert_eq!(r2, 2);
}

// The following two tests are taken from Repairing Sequential Consistency in C/C++11
// by Lahav et al.
// https://plv.mpi-sws.org/scfix/paper.pdf

// Test case SB
fn test_sc_store_buffering() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, SeqCst);
        y.load(SeqCst)
    });

    let j2 = spawn(move || {
        y.store(1, SeqCst);
        x.load(SeqCst)
    });

    let a = j1.join().unwrap();
    let b = j2.join().unwrap();

    assert_ne!((a, b), (0, 0));
}

fn test_single_thread() {
    let x = AtomicUsize::new(42);

    assert_eq!(x.load(Relaxed), 42);

    x.store(43, Relaxed);

    assert_eq!(x.load(Relaxed), 43);
}

pub fn main() {
    for _ in 0..50 {
        test_single_thread();
        test_mixed_access();
        test_load_buffering_acq_rel();
        test_message_passing();
        test_wrc();
        test_corr();
        test_sc_store_buffering();
    }
}
<commit_msg>add another weak mem consistency test<commit_after>//@ignore-windows: Concurrency on Windows is not supported yet.
//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows

// The following tests check whether our weak memory emulation produces
// any inconsistent execution outcomes
//
// Due to the random nature of choosing valid stores, it is always
// possible that our tests spuriously succeeds: even though our weak
// memory emulation code has incorrectly identified a store in
// modification order as being valid, it may be never chosen by
// the RNG and never observed in our tests.
//
// To mitigate this, each test is ran enough times such that the chance
// of spurious success is very low. These tests never supriously fail.

// Test cases and their consistent outcomes are from
// http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/
// Based on
// M. Batty, S. Owens, S. Sarkar, P. Sewell and T. Weber,
// "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011.
// Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf.

use std::sync::atomic::Ordering::*;
use std::sync::atomic::{fence, AtomicBool, AtomicI32};
use std::thread::spawn;

#[derive(Copy, Clone)]
struct EvilSend<T>(pub T);

unsafe impl<T> Send for EvilSend<T> {}
unsafe impl<T> Sync for EvilSend<T> {}

// We can't create static items because we need to run each test
// multiple times
fn static_atomic(val: i32) -> &'static AtomicI32 {
    let ret = Box::leak(Box::new(AtomicI32::new(val)));
    ret
}
fn static_atomic_bool(val: bool) -> &'static AtomicBool {
    let ret = Box::leak(Box::new(AtomicBool::new(val)));
    ret
}

// Spins until it acquires a pre-determined value.
fn acquires_value(loc: &AtomicI32, val: i32) -> i32 {
    while loc.load(Acquire) != val {
        std::hint::spin_loop();
    }
    val
}

fn test_corr() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, Relaxed);
        x.store(2, Relaxed);
    });

    #[rustfmt::skip]
    let j2 = spawn(move || {
        let r2 = x.load(Relaxed); // -------------------------------------+
        y.store(1, Release); // ---------------------+                    |
        r2 //                                        |                    |
    }); //                                           |                    |
    #[rustfmt::skip] //                              |synchronizes-with   |happens-before
    let j3 = spawn(move || { //                      |                    |
        acquires_value(&y, 1); // <------------------+                    |
        x.load(Relaxed) // <----------------------------------------------+
        // The two reads on x are ordered by hb, so they cannot observe values
        // differently from the modification order. If the first read observed
        // 2, then the second read must observe 2 as well.
    });

    j1.join().unwrap();
    let r2 = j2.join().unwrap();
    let r3 = j3.join().unwrap();
    if r2 == 2 {
        assert_eq!(r3, 2);
    }
}

fn test_wrc() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    #[rustfmt::skip]
    let j1 = spawn(move || {
        x.store(1, Release); // ---------------------+---------------------+
    }); //                                           |                     |
    #[rustfmt::skip] //                              |synchronizes-with    |
    let j2 = spawn(move || { //                      |                     |
        acquires_value(&x, 1); // <------------------+                     |
        y.store(1, Release); // ---------------------+                     |happens-before
    }); //                                           |                     |
    #[rustfmt::skip] //                              |synchronizes-with    |
    let j3 = spawn(move || { //                      |                     |
        acquires_value(&y, 1); // <------------------+                     |
        x.load(Relaxed) // <-----------------------------------------------+
    });

    j1.join().unwrap();
    j2.join().unwrap();
    let r3 = j3.join().unwrap();

    assert_eq!(r3, 1);
}

fn test_message_passing() {
    let mut var = 0u32;
    let ptr = &mut var as *mut u32;
    let x = EvilSend(ptr);
    let y = static_atomic(0);

    #[rustfmt::skip]
    let j1 = spawn(move || {
        unsafe { *x.0 = 1 }; // -----------------------------------------+
        y.store(1, Release); // ---------------------+                   |
    }); //                                           |                   |
    #[rustfmt::skip] //                              |synchronizes-with  | happens-before
    let j2 = spawn(move || { //                      |                   |
        acquires_value(&y, 1); // <------------------+                   |
        unsafe { *x.0 } // <---------------------------------------------+
    });

    j1.join().unwrap();
    let r2 = j2.join().unwrap();

    assert_eq!(r2, 1);
}

// LB+acq_rel+acq_rel
fn test_load_buffering_acq_rel() {
    let x = static_atomic(0);
    let y = static_atomic(0);
    let j1 = spawn(move || {
        let r1 = x.load(Acquire);
        y.store(1, Release);
        r1
    });

    let j2 = spawn(move || {
        let r2 = y.load(Acquire);
        x.store(1, Release);
        r2
    });

    let r1 = j1.join().unwrap();
    let r2 = j2.join().unwrap();

    // 3 consistent outcomes: (0,0), (0,1), (1,0)
    assert_ne!((r1, r2), (1, 1));
}

fn test_mixed_access() {
    /*
    int main() {
      atomic_int x = 0;
      {{{
        x.store(1, mo_relaxed);
      }}}

      x.store(2, mo_relaxed);

      {{{
        r1 = x.load(mo_relaxed);
      }}}

      return 0;
    }
        */
    let x = static_atomic(0);

    spawn(move || {
        x.store(1, Relaxed);
    })
    .join()
    .unwrap();

    x.store(2, Relaxed);

    let r2 = spawn(move || x.load(Relaxed)).join().unwrap();

    assert_eq!(r2, 2);
}

// The following two tests are taken from Repairing Sequential Consistency in C/C++11
// by Lahav et al.
// https://plv.mpi-sws.org/scfix/paper.pdf

// Test case SB
fn test_sc_store_buffering() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, SeqCst);
        y.load(SeqCst)
    });

    let j2 = spawn(move || {
        y.store(1, SeqCst);
        x.load(SeqCst)
    });

    let a = j1.join().unwrap();
    let b = j2.join().unwrap();

    assert_ne!((a, b), (0, 0));
}

fn test_single_thread() {
    let x = AtomicI32::new(42);

    assert_eq!(x.load(Relaxed), 42);

    x.store(43, Relaxed);

    assert_eq!(x.load(Relaxed), 43);
}

fn test_sync_through_rmw_and_fences() {
    // Example from https://github.com/llvm/llvm-project/issues/56450#issuecomment-1183695905
    #[no_mangle]
    pub fn rdmw(storing: &AtomicI32, sync: &AtomicI32, loading: &AtomicI32) -> i32 {
        storing.store(1, Relaxed);
        fence(Release);
        sync.fetch_add(0, Relaxed);
        fence(Acquire);
        loading.load(Relaxed)
    }

    let x = static_atomic(0);
    let y = static_atomic(0);
    let z = static_atomic(0);

    // Since each thread is so short, we need to make sure that they truely run at the same time
    // Otherwise t1 will finish before t2 even starts
    let go = static_atomic_bool(false);

    let t1 = spawn(move || {
        while !go.load(Relaxed) {}
        rdmw(y, x, z)
    });

    let t2 = spawn(move || {
        while !go.load(Relaxed) {}
        rdmw(z, x, y)
    });

    go.store(true, Relaxed);

    let a = t1.join().unwrap();
    let b = t2.join().unwrap();
    assert_ne!((a, b), (0, 0));
}

pub fn main() {
    for _ in 0..50 {
        test_single_thread();
        test_mixed_access();
        test_load_buffering_acq_rel();
        test_message_passing();
        test_wrc();
        test_corr();
        test_sc_store_buffering();
        test_sync_through_rmw_and_fences();
    }
}
<|endoftext|>


<commit_before>//! Finding the dominators in a control-flow graph.
//!
//! Algorithm based on Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy,
//! "A Simple, Fast Dominance Algorithm",
//! Rice Computer Science TS-06-33870,
//! <https://www.cs.rice.edu/~keith/EMBED/dom.pdf>.

use super::iterate::reverse_post_order;
use super::ControlFlowGraph;
use rustc_index::vec::{Idx, IndexVec};
use std::borrow::BorrowMut;
use std::cmp::Ordering;

#[cfg(test)]
mod tests;

pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
    let start_node = graph.start_node();
    let rpo = reverse_post_order(&graph, start_node);
    dominators_given_rpo(graph, &rpo)
}

fn dominators_given_rpo<G: ControlFlowGraph + BorrowMut<G>>(
    mut graph: G,
    rpo: &[G::Node],
) -> Dominators<G::Node> {
    let start_node = graph.borrow().start_node();
    assert_eq!(rpo[0], start_node);

    // compute the post order index (rank) for each node
    let mut post_order_rank: IndexVec<G::Node, usize> =
        (0..graph.borrow().num_nodes()).map(|_| 0).collect();
    for (index, node) in rpo.iter().rev().cloned().enumerate() {
        post_order_rank[node] = index;
    }

    let mut immediate_dominators: IndexVec<G::Node, Option<G::Node>> =
        (0..graph.borrow().num_nodes()).map(|_| None).collect();
    immediate_dominators[start_node] = Some(start_node);

    let mut changed = true;
    while changed {
        changed = false;

        for &node in &rpo[1..] {
            let mut new_idom = None;
            for pred in graph.borrow_mut().predecessors(node) {
                if immediate_dominators[pred].is_some() {
                    // (*) dominators for `pred` have been calculated
                    new_idom = Some(if let Some(new_idom) = new_idom {
                        intersect(&post_order_rank, &immediate_dominators, new_idom, pred)
                    } else {
                        pred
                    });
                }
            }

            if new_idom != immediate_dominators[node] {
                immediate_dominators[node] = new_idom;
                changed = true;
            }
        }
    }

    Dominators { post_order_rank, immediate_dominators }
}

fn intersect<Node: Idx>(
    post_order_rank: &IndexVec<Node, usize>,
    immediate_dominators: &IndexVec<Node, Option<Node>>,
    mut node1: Node,
    mut node2: Node,
) -> Node {
    while node1 != node2 {
        while post_order_rank[node1] < post_order_rank[node2] {
            node1 = immediate_dominators[node1].unwrap();
        }

        while post_order_rank[node2] < post_order_rank[node1] {
            node2 = immediate_dominators[node2].unwrap();
        }
    }

    node1
}

#[derive(Clone, Debug)]
pub struct Dominators<N: Idx> {
    post_order_rank: IndexVec<N, usize>,
    immediate_dominators: IndexVec<N, Option<N>>,
}

impl<Node: Idx> Dominators<Node> {
    pub fn is_reachable(&self, node: Node) -> bool {
        self.immediate_dominators[node].is_some()
    }

    pub fn immediate_dominator(&self, node: Node) -> Node {
        assert!(self.is_reachable(node), "node {:?} is not reachable", node);
        self.immediate_dominators[node].unwrap()
    }

    pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
        assert!(self.is_reachable(node), "node {:?} is not reachable", node);
        Iter { dominators: self, node: Some(node) }
    }

    pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool {
        // FIXME -- could be optimized by using post-order-rank
        self.dominators(node).any(|n| n == dom)
    }

    /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator
    /// relationship, the dominator will always precede the dominated. (The relative ordering
    /// of two unrelated nodes will also be consistent, but otherwise the order has no
    /// meaning.) This method cannot be used to determine if either Node dominates the other.
    pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option<Ordering> {
        self.post_order_rank[lhs].partial_cmp(&self.post_order_rank[rhs])
    }
}

pub struct Iter<'dom, Node: Idx> {
    dominators: &'dom Dominators<Node>,
    node: Option<Node>,
}

impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
    type Item = Node;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(node) = self.node {
            let dom = self.dominators.immediate_dominator(node);
            if dom == node {
                self.node = None; // reached the root
            } else {
                self.node = Some(dom);
            }
            Some(node)
        } else {
            None
        }
    }
}
<commit_msg>Rollup merge of #81338 - bugadani:dominator-cleanup, r=davidtwco<commit_after>//! Finding the dominators in a control-flow graph.
//!
//! Algorithm based on Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy,
//! "A Simple, Fast Dominance Algorithm",
//! Rice Computer Science TS-06-33870,
//! <https://www.cs.rice.edu/~keith/EMBED/dom.pdf>.

use super::iterate::reverse_post_order;
use super::ControlFlowGraph;
use rustc_index::vec::{Idx, IndexVec};
use std::cmp::Ordering;

#[cfg(test)]
mod tests;

pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
    let start_node = graph.start_node();
    let rpo = reverse_post_order(&graph, start_node);
    dominators_given_rpo(graph, &rpo)
}

fn dominators_given_rpo<G: ControlFlowGraph>(graph: G, rpo: &[G::Node]) -> Dominators<G::Node> {
    let start_node = graph.start_node();
    assert_eq!(rpo[0], start_node);

    // compute the post order index (rank) for each node
    let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
    for (index, node) in rpo.iter().rev().cloned().enumerate() {
        post_order_rank[node] = index;
    }

    let mut immediate_dominators = IndexVec::from_elem_n(None, graph.num_nodes());
    immediate_dominators[start_node] = Some(start_node);

    let mut changed = true;
    while changed {
        changed = false;

        for &node in &rpo[1..] {
            let mut new_idom = None;
            for pred in graph.predecessors(node) {
                if immediate_dominators[pred].is_some() {
                    // (*) dominators for `pred` have been calculated
                    new_idom = Some(if let Some(new_idom) = new_idom {
                        intersect(&post_order_rank, &immediate_dominators, new_idom, pred)
                    } else {
                        pred
                    });
                }
            }

            if new_idom != immediate_dominators[node] {
                immediate_dominators[node] = new_idom;
                changed = true;
            }
        }
    }

    Dominators { post_order_rank, immediate_dominators }
}

fn intersect<Node: Idx>(
    post_order_rank: &IndexVec<Node, usize>,
    immediate_dominators: &IndexVec<Node, Option<Node>>,
    mut node1: Node,
    mut node2: Node,
) -> Node {
    while node1 != node2 {
        while post_order_rank[node1] < post_order_rank[node2] {
            node1 = immediate_dominators[node1].unwrap();
        }

        while post_order_rank[node2] < post_order_rank[node1] {
            node2 = immediate_dominators[node2].unwrap();
        }
    }

    node1
}

#[derive(Clone, Debug)]
pub struct Dominators<N: Idx> {
    post_order_rank: IndexVec<N, usize>,
    immediate_dominators: IndexVec<N, Option<N>>,
}

impl<Node: Idx> Dominators<Node> {
    pub fn is_reachable(&self, node: Node) -> bool {
        self.immediate_dominators[node].is_some()
    }

    pub fn immediate_dominator(&self, node: Node) -> Node {
        assert!(self.is_reachable(node), "node {:?} is not reachable", node);
        self.immediate_dominators[node].unwrap()
    }

    pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
        assert!(self.is_reachable(node), "node {:?} is not reachable", node);
        Iter { dominators: self, node: Some(node) }
    }

    pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool {
        // FIXME -- could be optimized by using post-order-rank
        self.dominators(node).any(|n| n == dom)
    }

    /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator
    /// relationship, the dominator will always precede the dominated. (The relative ordering
    /// of two unrelated nodes will also be consistent, but otherwise the order has no
    /// meaning.) This method cannot be used to determine if either Node dominates the other.
    pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option<Ordering> {
        self.post_order_rank[lhs].partial_cmp(&self.post_order_rank[rhs])
    }
}

pub struct Iter<'dom, Node: Idx> {
    dominators: &'dom Dominators<Node>,
    node: Option<Node>,
}

impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
    type Item = Node;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(node) = self.node {
            let dom = self.dominators.immediate_dominator(node);
            if dom == node {
                self.node = None; // reached the root
            } else {
                self.node = Some(dom);
            }
            Some(node)
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>extern crate csv;
#[macro_use]
extern crate error_chain;
extern crate flate2;
extern crate tar;
extern crate unicode_casefold;
extern crate unicode_segmentation;

use std::cmp::Ordering;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::io;
use std::io::prelude::*;
use unicode_casefold::{Locale, UnicodeCaseFold, Variant};
use unicode_segmentation::UnicodeSegmentation;

mod errors;

pub use self::errors::{Result, Error, ErrorKind};

const MODEL_SIZE_LIMIT: usize = 10000;

/// Used to build a "language model" describing a human language, where the
/// input data is assumed to come from subtitle files.
pub struct ModelBuilder {
    grapheme_counts: HashMap<String, u64>,
    pair_counts: HashMap<String, u64>,
    word_counts: HashMap<String, u64>,
}

impl ModelBuilder {
    /// Create a new `ModelBuilder`.
    pub fn new() -> ModelBuilder {
        ModelBuilder {
            grapheme_counts: HashMap::new(),
            pair_counts: HashMap::new(),
            word_counts: HashMap::new(),
        }
    }

    /// Add a subtitle line to the `ModelBuilder`.
    pub fn add_line(&mut self, line: &str) {
        let grapheme_buffer = line.graphemes(true).collect::<Vec<_>>();
        for &grapheme in &grapheme_buffer {
            if grapheme != " " {
                incr_map(&mut self.grapheme_counts, grapheme.to_owned());
            }
        }
        if !grapheme_buffer.is_empty() {
            incr_map(&mut self.pair_counts, format!("\n{}", grapheme_buffer[0]));
            incr_map(&mut self.pair_counts,
                     format!("{}\n", grapheme_buffer[grapheme_buffer.len() - 1]));
        }
        for pair in grapheme_buffer.windows(2) {
            incr_map(&mut self.pair_counts, format!("{}{}", pair[0], pair[1]));
        }
        for word in line.unicode_words() {
            // TODO: Handle Turkic "i".
            let word = word.case_fold_with(Variant::Full, Locale::NonTurkic).collect();
            incr_map(&mut self.word_counts, word);
        }
    }

    /// Write our current grapheme frequencies to `out`.
    pub fn grapheme_frequencies<W: Write>(&self, out: W) -> Result<()> {
        self.frequencies(&self.grapheme_counts, out)
    }

    /// Write our current pair frequencies to `out`.
    pub fn pair_frequencies<W: Write>(&self, out: W) -> Result<()> {
        self.frequencies(&self.pair_counts, out)
    }

    /// Write our current word frequencies to `out`.
    pub fn word_frequencies<W: Write>(&self, out: W) -> Result<()> {
        self.frequencies(&self.word_counts, out)
    }

    /// Write the frequencies in `counts` to `out`, labelling them with
    /// `label`.
    fn frequencies<W: Write>(&self,
                             counts: &HashMap<String, u64>,
                             out: W)
                             -> Result<()> {
        // Count the total number of graphemes we've seen.
        let mut total: f64 = 0.0;
        for &count in counts.values() {
            total += count as f64;
        }

        // Sort our results into a stable order and replace counts with
        // probabilities.
        let mut rows = counts.iter().collect::<Vec<_>>();
        rows.sort_by(|&(k1, c1), &(k2, c2)| match c1.cmp(c2).reverse() {
                         Ordering::Equal => k1.cmp(k2),
                         other => other,
                     });

        // Write output to a CSV.
        let mut wtr = csv::Writer::from_writer(out);
        for (key, &count) in rows.into_iter().take(MODEL_SIZE_LIMIT) {
            wtr.encode((key, count as f64 / total))?;
        }
        Ok(())
    }

    /// Write out our language model to `out`.  This is actually a gzipped
    /// tar file containing multiple CSV files:
    ///
    /// - `graphemes.csv`: Frequencies of single grapheme clusters.
    /// - `pairs.csv`: Frequencies of grapheme pairs.
    /// - `words.csv`: Frequencies of case-folded words.
    ///
    /// All models will be truncted if they exceed a certain limit.
    pub fn write_model<W: Write>(&self, out: W) -> Result<()> {
        let gzip = flate2::write::GzEncoder::new(out, flate2::Compression::Best);
        let mut tar = tar::Builder::new(gzip);
        self.append_model_part(&mut tar, "graphemes.csv", &self.grapheme_counts)?;
        self.append_model_part(&mut tar, "pairs.csv", &self.pair_counts)?;
        self.append_model_part(&mut tar, "words.csv", &self.word_counts)?;
        tar.into_inner()?.finish()?;
        Ok(())
    }

    /// Append a file to our model.
    fn append_model_part<W: Write>(&self,
                                   builder: &mut tar::Builder<W>,
                                   path: &str,
                                   counts: &HashMap<String, u64>)
                                   -> Result<()> {
        let mut csv = vec![];
        self.frequencies(counts, &mut csv)?;

        let mut header = tar::Header::new_old();
        header.set_path(path)?;
        // TODO: Can this fail with a cast error?
        header.set_size(csv.len() as u64);
        header.set_mode(0o500);
        header.set_cksum();
        builder.append(&header, io::Cursor::new(&csv))?;
        Ok(())
    }
}

/// Increment a key in a map.
fn incr_map(map: &mut HashMap<String, u64>, key: String) {
    match map.entry(key.to_owned()) {
        Entry::Occupied(mut occupied) => {
            *occupied.get_mut() += 1;
        }
        Entry::Vacant(vacant) => {
            vacant.insert(1);
        }
    }
}

#[test]
fn grapheme_frequency() {
    use std::str;

    let mut builder = ModelBuilder::new();
    builder.add_line("Hello world");
    let mut csv = vec![];
    builder.grapheme_frequencies(&mut csv).unwrap();
    assert_eq!(str::from_utf8(&csv).unwrap(),
               "\
l,0.3
o,0.2
H,0.1
d,0.1
e,0.1
r,0.1
w,0.1
");
}

#[test]
fn pair_frequency() {
    use std::str;

    let mut builder = ModelBuilder::new();
    builder.add_line("Help");
    let mut csv = vec![];
    builder.pair_frequencies(&mut csv).unwrap();
    assert_eq!(str::from_utf8(&csv).unwrap(),
               "\
\"\nH\",0.2
He,0.2
el,0.2
lp,0.2
\"p\n\",0.2
");
}

#[test]
fn word_frequency() {
    use std::str;

    let mut builder = ModelBuilder::new();
    builder.add_line("One potato, two potato!");
    let mut csv = vec![];
    builder.word_frequencies(&mut csv).unwrap();
    assert_eq!(str::from_utf8(&csv).unwrap(),
               "\
potato,0.5
one,0.25
two,0.25
");
}

#[test]
fn write_model() {
    let mut builder = ModelBuilder::new();
    builder.add_line("One potato, two potato!");
    let mut model = vec![];
    builder.write_model(&mut model).unwrap();
    assert!(model.len() > 0);
}
<commit_msg>submodel: Fix permissions on model tar achive<commit_after>extern crate csv;
#[macro_use]
extern crate error_chain;
extern crate flate2;
extern crate tar;
extern crate unicode_casefold;
extern crate unicode_segmentation;

use std::cmp::Ordering;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::io;
use std::io::prelude::*;
use unicode_casefold::{Locale, UnicodeCaseFold, Variant};
use unicode_segmentation::UnicodeSegmentation;

mod errors;

pub use self::errors::{Result, Error, ErrorKind};

const MODEL_SIZE_LIMIT: usize = 10000;

/// Used to build a "language model" describing a human language, where the
/// input data is assumed to come from subtitle files.
pub struct ModelBuilder {
    grapheme_counts: HashMap<String, u64>,
    pair_counts: HashMap<String, u64>,
    word_counts: HashMap<String, u64>,
}

impl ModelBuilder {
    /// Create a new `ModelBuilder`.
    pub fn new() -> ModelBuilder {
        ModelBuilder {
            grapheme_counts: HashMap::new(),
            pair_counts: HashMap::new(),
            word_counts: HashMap::new(),
        }
    }

    /// Add a subtitle line to the `ModelBuilder`.
    pub fn add_line(&mut self, line: &str) {
        let grapheme_buffer = line.graphemes(true).collect::<Vec<_>>();
        for &grapheme in &grapheme_buffer {
            if grapheme != " " {
                incr_map(&mut self.grapheme_counts, grapheme.to_owned());
            }
        }
        if !grapheme_buffer.is_empty() {
            incr_map(&mut self.pair_counts, format!("\n{}", grapheme_buffer[0]));
            incr_map(&mut self.pair_counts,
                     format!("{}\n", grapheme_buffer[grapheme_buffer.len() - 1]));
        }
        for pair in grapheme_buffer.windows(2) {
            incr_map(&mut self.pair_counts, format!("{}{}", pair[0], pair[1]));
        }
        for word in line.unicode_words() {
            // TODO: Handle Turkic "i".
            let word = word.case_fold_with(Variant::Full, Locale::NonTurkic).collect();
            incr_map(&mut self.word_counts, word);
        }
    }

    /// Write our current grapheme frequencies to `out`.
    pub fn grapheme_frequencies<W: Write>(&self, out: W) -> Result<()> {
        self.frequencies(&self.grapheme_counts, out)
    }

    /// Write our current pair frequencies to `out`.
    pub fn pair_frequencies<W: Write>(&self, out: W) -> Result<()> {
        self.frequencies(&self.pair_counts, out)
    }

    /// Write our current word frequencies to `out`.
    pub fn word_frequencies<W: Write>(&self, out: W) -> Result<()> {
        self.frequencies(&self.word_counts, out)
    }

    /// Write the frequencies in `counts` to `out`, labelling them with
    /// `label`.
    fn frequencies<W: Write>(&self,
                             counts: &HashMap<String, u64>,
                             out: W)
                             -> Result<()> {
        // Count the total number of graphemes we've seen.
        let mut total: f64 = 0.0;
        for &count in counts.values() {
            total += count as f64;
        }

        // Sort our results into a stable order and replace counts with
        // probabilities.
        let mut rows = counts.iter().collect::<Vec<_>>();
        rows.sort_by(|&(k1, c1), &(k2, c2)| match c1.cmp(c2).reverse() {
                         Ordering::Equal => k1.cmp(k2),
                         other => other,
                     });

        // Write output to a CSV.
        let mut wtr = csv::Writer::from_writer(out);
        for (key, &count) in rows.into_iter().take(MODEL_SIZE_LIMIT) {
            wtr.encode((key, count as f64 / total))?;
        }
        Ok(())
    }

    /// Write out our language model to `out`.  This is actually a gzipped
    /// tar file containing multiple CSV files:
    ///
    /// - `graphemes.csv`: Frequencies of single grapheme clusters.
    /// - `pairs.csv`: Frequencies of grapheme pairs.
    /// - `words.csv`: Frequencies of case-folded words.
    ///
    /// All models will be truncted if they exceed a certain limit.
    pub fn write_model<W: Write>(&self, out: W) -> Result<()> {
        let gzip = flate2::write::GzEncoder::new(out, flate2::Compression::Best);
        let mut tar = tar::Builder::new(gzip);
        self.append_model_part(&mut tar, "graphemes.csv", &self.grapheme_counts)?;
        self.append_model_part(&mut tar, "pairs.csv", &self.pair_counts)?;
        self.append_model_part(&mut tar, "words.csv", &self.word_counts)?;
        tar.into_inner()?.finish()?;
        Ok(())
    }

    /// Append a file to our model.
    fn append_model_part<W: Write>(&self,
                                   builder: &mut tar::Builder<W>,
                                   path: &str,
                                   counts: &HashMap<String, u64>)
                                   -> Result<()> {
        let mut csv = vec![];
        self.frequencies(counts, &mut csv)?;

        let mut header = tar::Header::new_old();
        header.set_path(path)?;
        // TODO: Can this fail with a cast error?
        header.set_size(csv.len() as u64);
        header.set_mode(0o600);
        header.set_cksum();
        builder.append(&header, io::Cursor::new(&csv))?;
        Ok(())
    }
}

/// Increment a key in a map.
fn incr_map(map: &mut HashMap<String, u64>, key: String) {
    match map.entry(key.to_owned()) {
        Entry::Occupied(mut occupied) => {
            *occupied.get_mut() += 1;
        }
        Entry::Vacant(vacant) => {
            vacant.insert(1);
        }
    }
}

#[test]
fn grapheme_frequency() {
    use std::str;

    let mut builder = ModelBuilder::new();
    builder.add_line("Hello world");
    let mut csv = vec![];
    builder.grapheme_frequencies(&mut csv).unwrap();
    assert_eq!(str::from_utf8(&csv).unwrap(),
               "\
l,0.3
o,0.2
H,0.1
d,0.1
e,0.1
r,0.1
w,0.1
");
}

#[test]
fn pair_frequency() {
    use std::str;

    let mut builder = ModelBuilder::new();
    builder.add_line("Help");
    let mut csv = vec![];
    builder.pair_frequencies(&mut csv).unwrap();
    assert_eq!(str::from_utf8(&csv).unwrap(),
               "\
\"\nH\",0.2
He,0.2
el,0.2
lp,0.2
\"p\n\",0.2
");
}

#[test]
fn word_frequency() {
    use std::str;

    let mut builder = ModelBuilder::new();
    builder.add_line("One potato, two potato!");
    let mut csv = vec![];
    builder.word_frequencies(&mut csv).unwrap();
    assert_eq!(str::from_utf8(&csv).unwrap(),
               "\
potato,0.5
one,0.25
two,0.25
");
}

#[test]
fn write_model() {
    let mut builder = ModelBuilder::new();
    builder.add_line("One potato, two potato!");
    let mut model = vec![];
    builder.write_model(&mut model).unwrap();
    assert!(model.len() > 0);
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;
extern crate extra;
extern crate syscall;

use std::env;
use std::fs::File;
use std::io::{stdout, stderr, Error, Write};
use std::os::unix::io::AsRawFd;
use std::process::exit;
use coreutils::ArgParser;
use extra::io::fail;
use extra::option::OptionalExt;
use syscall::data::StatVfs;

const MAN_PAGE: &'static str = /* @MANSTART{df} */ r#"
NAME
    df - view filesystem space usage

SYNOPSIS
    df [ -h | --help ] FILE...

DESCRIPTION
    df gets the filesystem space usage for the filesystem providing FILE

OPTIONS
    -h
    --help
        display this help and exit
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag("h", "help");
    parser.initialize(env::args());

    if parser.flagged(&'h') || parser.flagged("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    if parser.args.is_empty() {
        fail("No arguments. Use --help to see the usage.", &mut stderr);
    }

    println!("{:<8}{:<8}{:<8}{:<5}", "Size", "Used", "Free", "Use%");
    for path in &parser.args {
        let mut stat = StatVfs::default();
        {
            let file = File::open(&path).try(&mut stderr);
            syscall::fstatvfs(file.as_raw_fd(), &mut stat).map_err(|err| Error::from_raw_os_error(err.errno)).try(&mut stderr);
        }

        let size = stat.f_blocks * stat.f_bsize as u64 / 1024;
        let used = (stat.f_blocks - stat.f_bfree) * stat.f_bsize as u64 / 1024;
        let free = stat.f_bavail * stat.f_bsize as u64 / 1024;
        let percent = (100.0 * used as f64 / size as f64) as u64;
        println!("{:<8}{:<8}{:<8}{:<5}", size, used, free, format!("{}%", percent));
    }
}
<commit_msg>Use O_STAT to open fd for fstatvfs<commit_after>#![deny(warnings)]

extern crate coreutils;
extern crate extra;
extern crate syscall;

use std::env;
use std::io::{stdout, stderr, Error, Write};
use std::process::exit;
use coreutils::ArgParser;
use extra::io::fail;
use extra::option::OptionalExt;
use syscall::data::StatVfs;

const MAN_PAGE: &'static str = /* @MANSTART{df} */ r#"
NAME
    df - view filesystem space usage

SYNOPSIS
    df [ -h | --help ] FILE...

DESCRIPTION
    df gets the filesystem space usage for the filesystem providing FILE

OPTIONS
    -h
    --help
        display this help and exit
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag("h", "help");
    parser.initialize(env::args());

    if parser.flagged(&'h') || parser.flagged("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    if parser.args.is_empty() {
        fail("No arguments. Use --help to see the usage.", &mut stderr);
    }

    println!("{:<8}{:<8}{:<8}{:<5}", "Size", "Used", "Free", "Use%");
    for path in &parser.args {
        let mut stat = StatVfs::default();
        {
            let fd = syscall::open(&path, syscall::O_STAT).map_err(|err| Error::from_raw_os_error(err.errno)).try(&mut stderr);
            syscall::fstatvfs(fd, &mut stat).map_err(|err| Error::from_raw_os_error(err.errno)).try(&mut stderr);
            let _ = syscall::close(fd);
        }

        let size = stat.f_blocks * stat.f_bsize as u64 / 1024;
        let used = (stat.f_blocks - stat.f_bfree) * stat.f_bsize as u64 / 1024;
        let free = stat.f_bavail * stat.f_bsize as u64 / 1024;
        let percent = (100.0 * used as f64 / size as f64) as u64;
        println!("{:<8}{:<8}{:<8}{:<5}", size, used, free, format!("{}%", percent));
    }
}
<|endoftext|>


<commit_before>extern crate bindgen;
extern crate gcc;
extern crate gl_generator;
#[cfg(feature = "static")]
extern crate meson;
extern crate wayland_scanner;

use gl_generator::{Api, Fallbacks, Profile, Registry, StaticGenerator};
use std::env;
use std::fs::File;
#[allow(unused_imports)]
use std::path::{Path, PathBuf};

fn main() {
    meson();
    let target_dir = env::var("OUT_DIR").expect("$OUT_DIR not set!");
    let generated = bindgen::builder()
        .derive_debug(true)
        .derive_default(true)
        .generate_comments(true)
        .header("src/wlroots.h")
        .whitelisted_type(r"^wlr_.*$")
        .whitelisted_type(r"^xkb_.*$")
        .whitelisted_type(r"^XKB_.*$")
        .whitelisted_function(r"^_?wlr_.*$")
        .whitelisted_function(r"^xkb_.*$")
        .ctypes_prefix("libc")
        .clang_arg("-Iwlroots/include")
        .clang_arg("-Iwlroots/include/wlr")
        // NOTE Necessary because they use the out directory to put
        // pragma information on what features are available in a header file
        // titled "config.h"
        .clang_arg(format!("-I{}{}", target_dir, "/include/"))
        // NOTE Necessary because the xdg-shell-v6 headers generate here
        .clang_arg(format!("-I{}{}", target_dir, "/protocol/wl_protos@sta"))
        .clang_arg("-Iwlroots/include/xcursor")
        .clang_arg("-I/usr/include/pixman-1")
        // Work around bug https://github.com/rust-lang-nursery/rust-bindgen/issues/687
        .hide_type("FP_NAN")
        .hide_type("FP_INFINITE")
        .hide_type("FP_ZERO")
        .hide_type("FP_SUBNORMAL")
        .hide_type("FP_NORMAL")
        .generate().unwrap();

    println!("cargo:rustc-link-lib=dylib=X11");
    println!("cargo:rustc-link-lib=dylib=X11-xcb");
    println!("cargo:rustc-link-lib=dylib=xkbcommon");
    println!("cargo:rustc-link-lib=dylib=xcb");
    println!("cargo:rustc-link-lib=dylib=cap");
    println!("cargo:rustc-link-lib=dylib=wayland-egl");
    println!("cargo:rustc-link-lib=dylib=wayland-client");
    println!("cargo:rustc-link-lib=dylib=wayland-server");
    println!("cargo:rustc-link-lib=dylib=EGL");
    println!("cargo:rustc-link-lib=dylib=GL");
    println!("cargo:rustc-link-lib=dylib=gbm");
    println!("cargo:rustc-link-lib=dylib=drm");
    println!("cargo:rustc-link-lib=dylib=input");
    println!("cargo:rustc-link-lib=dylib=udev");
    println!("cargo:rustc-link-lib=dylib=systemd");
    println!("cargo:rustc-link-lib=dylib=dbus-1");
    println!("cargo:rustc-link-lib=dylib=pixman-1");

    if !cfg!(feature = "static") {
        println!("cargo:rustc-link-lib=dylib=wlroots");
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    // generate the bindings
    generated.write_to_file("src/gen.rs").unwrap();

    generate_protocols();

    // Example Khronos building stuff
    let mut file = File::create(&Path::new(&target_dir).join("bindings.rs")).unwrap();
    Registry::new(Api::Gl, (4, 5), Profile::Core, Fallbacks::All, [])
        .write_bindings(StaticGenerator, &mut file)
        .unwrap();
}

#[cfg(not(feature = "static"))]
fn meson() {}

#[cfg(feature = "static")]
fn meson() {
    let build_path =
        PathBuf::from(env::var("OUT_DIR").expect("Could not get OUT_DIR env variable"));
    build_path.join("build");
    let build_path_str = build_path.to_str()
                                   .expect("Could not turn build path into a string");
    println!("cargo:rustc-link-search=native=wlroots");
    println!("cargo:rustc-link-search=native={}/lib", build_path_str);
    println!("cargo:rustc-link-search=native={}/lib64", build_path_str);
    println!("cargo:rustc-link-search=native={}/build/", build_path_str);
    if cfg!(feature = "static") {
        println!("cargo:rustc-link-search=native={}/util/", build_path_str);
        println!("cargo:rustc-link-search=native={}/types/", build_path_str);
        println!("cargo:rustc-link-search=native={}/protocol/",
                 build_path_str);
        println!("cargo:rustc-link-search=native={}/xcursor/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xwayland/",
                 build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/", build_path_str);
        println!("cargo:rustc-link-search=native={}/render/", build_path_str);

        println!("cargo:rustc-link-lib=static=wlr_util");
        println!("cargo:rustc-link-lib=static=wlr_types");
        println!("cargo:rustc-link-lib=static=wlr_xcursor");
        println!("cargo:rustc-link-lib=static=wlr_xwayland");
        println!("cargo:rustc-link-lib=static=wlr_backend");
        println!("cargo:rustc-link-lib=static=wlr_render");
        // wayland protocols
        println!("cargo:rustc-link-lib=static=wl_protos");
    }

    meson::build("wlroots", build_path_str);
}

fn generate_protocols() {
    let output_dir_str = env::var("OUT_DIR").unwrap();

    let output_dir = Path::new(&output_dir_str);

    let protocols = &[("./wlroots/protocol/server-decoration.xml", "server_decoration")];

    for protocol in protocols {
        wayland_scanner::generate_code(protocol.0,
                                       output_dir.join(format!("{}_server_api.rs", protocol.1)),
                                       wayland_scanner::Side::Server);
        wayland_scanner::generate_code(protocol.0,
                                       output_dir.join(format!("{}_client_api.rs", protocol.1)),
                                       wayland_scanner::Side::Client);
        wayland_scanner::generate_interfaces(protocol.0,
                                             output_dir.join(format!("{}_interfaces.rs",
                                                                     protocol.1)));
    }
}
<commit_msg>Added linking to xcb libraries<commit_after>extern crate bindgen;
extern crate gcc;
extern crate gl_generator;
#[cfg(feature = "static")]
extern crate meson;
extern crate wayland_scanner;

use gl_generator::{Api, Fallbacks, Profile, Registry, StaticGenerator};
use std::env;
use std::fs::File;
#[allow(unused_imports)]
use std::path::{Path, PathBuf};

fn main() {
    meson();
    let target_dir = env::var("OUT_DIR").expect("$OUT_DIR not set!");
    let generated = bindgen::builder()
        .derive_debug(true)
        .derive_default(true)
        .generate_comments(true)
        .header("src/wlroots.h")
        .whitelisted_type(r"^wlr_.*$")
        .whitelisted_type(r"^xkb_.*$")
        .whitelisted_type(r"^XKB_.*$")
        .whitelisted_function(r"^_?wlr_.*$")
        .whitelisted_function(r"^xkb_.*$")
        .ctypes_prefix("libc")
        .clang_arg("-Iwlroots/include")
        .clang_arg("-Iwlroots/include/wlr")
        // NOTE Necessary because they use the out directory to put
        // pragma information on what features are available in a header file
        // titled "config.h"
        .clang_arg(format!("-I{}{}", target_dir, "/include/"))
        // NOTE Necessary because the xdg-shell-v6 headers generate here
        .clang_arg(format!("-I{}{}", target_dir, "/protocol/wl_protos@sta"))
        .clang_arg("-Iwlroots/include/xcursor")
        .clang_arg("-I/usr/include/pixman-1")
        // Work around bug https://github.com/rust-lang-nursery/rust-bindgen/issues/687
        .hide_type("FP_NAN")
        .hide_type("FP_INFINITE")
        .hide_type("FP_ZERO")
        .hide_type("FP_SUBNORMAL")
        .hide_type("FP_NORMAL")
        .generate().unwrap();

    println!("cargo:rustc-link-lib=dylib=X11");
    println!("cargo:rustc-link-lib=dylib=X11-xcb");
    println!("cargo:rustc-link-lib=dylib=xkbcommon");
    println!("cargo:rustc-link-lib=dylib=xcb");
    println!("cargo:rustc-link-lib=dylib=xcb-composite");
    println!("cargo:rustc-link-lib=dylib=xcb-xfixes");
    println!("cargo:rustc-link-lib=dylib=xcb-image");
    println!("cargo:rustc-link-lib=dylib=xcb-render");
    println!("cargo:rustc-link-lib=dylib=xcb-shm");
    println!("cargo:rustc-link-lib=dylib=xcb-icccm");
    println!("cargo:rustc-link-lib=dylib=xcb-xkb");
    println!("cargo:rustc-link-lib=dylib=cap");
    println!("cargo:rustc-link-lib=dylib=wayland-egl");
    println!("cargo:rustc-link-lib=dylib=wayland-client");
    println!("cargo:rustc-link-lib=dylib=wayland-server");
    println!("cargo:rustc-link-lib=dylib=EGL");
    println!("cargo:rustc-link-lib=dylib=GL");
    println!("cargo:rustc-link-lib=dylib=gbm");
    println!("cargo:rustc-link-lib=dylib=drm");
    println!("cargo:rustc-link-lib=dylib=input");
    println!("cargo:rustc-link-lib=dylib=udev");
    println!("cargo:rustc-link-lib=dylib=systemd");
    println!("cargo:rustc-link-lib=dylib=dbus-1");
    println!("cargo:rustc-link-lib=dylib=pixman-1");

    if !cfg!(feature = "static") {
        println!("cargo:rustc-link-lib=dylib=wlroots");
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    // generate the bindings
    generated.write_to_file("src/gen.rs").unwrap();

    generate_protocols();

    // Example Khronos building stuff
    let mut file = File::create(&Path::new(&target_dir).join("bindings.rs")).unwrap();
    Registry::new(Api::Gl, (4, 5), Profile::Core, Fallbacks::All, [])
        .write_bindings(StaticGenerator, &mut file)
        .unwrap();
}

#[cfg(not(feature = "static"))]
fn meson() {}

#[cfg(feature = "static")]
fn meson() {
    let build_path =
        PathBuf::from(env::var("OUT_DIR").expect("Could not get OUT_DIR env variable"));
    build_path.join("build");
    let build_path_str = build_path.to_str()
                                   .expect("Could not turn build path into a string");
    println!("cargo:rustc-link-search=native=wlroots");
    println!("cargo:rustc-link-search=native={}/lib", build_path_str);
    println!("cargo:rustc-link-search=native={}/lib64", build_path_str);
    println!("cargo:rustc-link-search=native={}/build/", build_path_str);
    if cfg!(feature = "static") {
        println!("cargo:rustc-link-search=native={}/util/", build_path_str);
        println!("cargo:rustc-link-search=native={}/types/", build_path_str);
        println!("cargo:rustc-link-search=native={}/protocol/",
                 build_path_str);
        println!("cargo:rustc-link-search=native={}/xcursor/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xwayland/",
                 build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/", build_path_str);
        println!("cargo:rustc-link-search=native={}/render/", build_path_str);

        println!("cargo:rustc-link-lib=static=wlr_util");
        println!("cargo:rustc-link-lib=static=wlr_types");
        println!("cargo:rustc-link-lib=static=wlr_xcursor");
        println!("cargo:rustc-link-lib=static=wlr_xwayland");
        println!("cargo:rustc-link-lib=static=wlr_backend");
        println!("cargo:rustc-link-lib=static=wlr_render");
        // wayland protocols
        println!("cargo:rustc-link-lib=static=wl_protos");
    }

    meson::build("wlroots", build_path_str);
}

fn generate_protocols() {
    let output_dir_str = env::var("OUT_DIR").unwrap();

    let output_dir = Path::new(&output_dir_str);

    let protocols = &[("./wlroots/protocol/server-decoration.xml", "server_decoration")];

    for protocol in protocols {
        wayland_scanner::generate_code(protocol.0,
                                       output_dir.join(format!("{}_server_api.rs", protocol.1)),
                                       wayland_scanner::Side::Server);
        wayland_scanner::generate_code(protocol.0,
                                       output_dir.join(format!("{}_client_api.rs", protocol.1)),
                                       wayland_scanner::Side::Client);
        wayland_scanner::generate_interfaces(protocol.0,
                                             output_dir.join(format!("{}_interfaces.rs",
                                                                     protocol.1)));
    }
}
<|endoftext|>