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

use to_str::{ToStr,ToStrConsume};
use str;
use cast;

#[cfg(test)]
pub struct Ascii { priv chr: u8 }

/// Datatype to hold one ascii character. It is 8 bit long.
#[cfg(notest)]
#[deriving(Clone, Eq, Ord)]
pub struct Ascii { priv chr: u8 }

pub impl Ascii {
    /// Converts a ascii character into a `u8`.
    fn to_byte(self) -> u8 {
        self.chr
    }

    /// Converts a ascii character into a `char`.
    fn to_char(self) -> char {
        self.chr as char
    }
}

impl ToStr for Ascii {
    fn to_str(&self) -> ~str { str::from_bytes(['\'' as u8, self.chr, '\'' as u8]) }
}

/// Trait for converting into an ascii type.
pub trait AsciiCast<T> {
    /// Convert to an ascii type
    fn to_ascii(&self) -> T;

    /// Check if convertible to ascii
    fn is_ascii(&self) -> bool;
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] {
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());

        unsafe{ cast::transmute(*self) }
    }

    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self str {
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());

        let (p,len): (*u8, uint) = unsafe{ cast::transmute(*self) };
        unsafe{ cast::transmute((p, len - 1))}
    }

    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl AsciiCast<Ascii> for u8 {
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self }
    }

    fn is_ascii(&self) -> bool {
        *self & 128 == 0u8
    }
}

impl AsciiCast<Ascii> for char {
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self as u8 }
    }

    fn is_ascii(&self) -> bool {
        *self - ('\x7F' & *self) == '\x00'
    }
}

/// Trait for copyless casting to an ascii vector.
pub trait OwnedAsciiCast {
    /// Take ownership and cast to an ascii vector without trailing zero element.
    fn to_ascii_consume(self) -> ~[Ascii];
}

impl OwnedAsciiCast for ~[u8] {
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());

        unsafe {cast::transmute(self)}
    }
}

impl OwnedAsciiCast for ~str {
    fn to_ascii_consume(self) -> ~[Ascii] {
        let mut s = self;
        unsafe {
            str::raw::pop_byte(&mut s);
            cast::transmute(s)
        }
    }
}

/// Trait for converting an ascii type to a string. Needed to convert `&[Ascii]` to `~str`
pub trait ToStrAscii {
    /// Convert to a string.
    fn to_str_ascii(&self) -> ~str;
}

impl<'self> ToStrAscii for &'self [Ascii] {
    fn to_str_ascii(&self) -> ~str {
        let mut cpy = self.to_owned();
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }
}

impl ToStrConsume for ~[Ascii] {
    fn to_str_consume(self) -> ~str {
        let mut cpy = self;
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }
}

// NOTE: Remove stage0 marker after snapshot
#[cfg(and(test, not(stage0)))]
mod tests {
    use super::*;
    use to_str::{ToStr,ToStrConsume};
    use str;
    use cast;

    macro_rules! v2ascii (
        ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
        (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
    )

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().to_byte(), 65u8);
        assert_eq!(65u8.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_byte(), 65u8);
    }

    #[test]
    fn test_ascii_vec() {
        assert_eq!((&[40u8, 32u8, 59u8]).to_ascii(), v2ascii!([40, 32, 59]));
        assert_eq!("( ;".to_ascii(),                 v2ascii!([40, 32, 59]));
        // FIXME: #5475 borrowchk error, owned vectors do not live long enough
        // if chained-from directly
        let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
        let v = ~"( ;";              assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
    }

    #[test]
    fn test_owned_ascii_vec() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(~"( ;".to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~"( ;".to_ascii_consume_with_null(), v2ascii!(~[40, 32, 59, 0]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume_with_null(),
        //           v2ascii!(~[40, 32, 59, 0]));
    }

    #[test]
    fn test_ascii_to_str() { assert_eq!(v2ascii!([40, 32, 59]).to_str_ascii(), ~"( ;"); }

    #[test]
    fn test_ascii_to_str_consume() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(v2ascii!(~[40, 32, 59]).to_str_consume(), ~"( ;");
    }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_u8_slice()  { (&[127u8, 128u8, 255u8]).to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
}

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

use to_str::{ToStr,ToStrConsume};
use str;
use cast;

#[cfg(test)]
pub struct Ascii { priv chr: u8 }

/// Datatype to hold one ascii character. It is 8 bit long.
#[cfg(notest)]
#[deriving(Clone, Eq, Ord)]
pub struct Ascii { priv chr: u8 }

pub impl Ascii {
    /// Converts a ascii character into a `u8`.
    #[inline(always)]
    fn to_byte(self) -> u8 {
        self.chr
    }

    /// Converts a ascii character into a `char`.
    #[inline(always)]
    fn to_char(self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline(always)]
    fn to_lower(self) -> Ascii {
        if self.chr >= 65 && self.chr <= 90 {
            Ascii{chr: self.chr | 0x20 }
        } else {
            self
        }
    }

    /// Convert to uppercase.
    #[inline(always)]
    fn to_upper(self) -> Ascii {
        if self.chr >= 97 && self.chr <= 122 {
            Ascii{chr: self.chr & !0x20 }
        } else {
            self
        }
    }

    // Compares two ascii characters of equality, ignoring case.
    #[inline(always)]
    fn eq_ignore_case(self, other: Ascii) -> bool {
        self.to_lower().chr == other.to_lower().chr
    }
}

impl ToStr for Ascii {
    #[inline(always)]
    fn to_str(&self) -> ~str { str::from_bytes(['\'' as u8, self.chr, '\'' as u8]) }
}

/// Trait for converting into an ascii type.
pub trait AsciiCast<T> {
    /// Convert to an ascii type
    fn to_ascii(&self) -> T;

    /// Check if convertible to ascii
    fn is_ascii(&self) -> bool;
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());

        unsafe{ cast::transmute(*self) }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self str {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());

        let (p,len): (*u8, uint) = unsafe{ cast::transmute(*self) };
        unsafe{ cast::transmute((p, len - 1))}
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl AsciiCast<Ascii> for u8 {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self & 128 == 0u8
    }
}

impl AsciiCast<Ascii> for char {

    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self as u8 }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self - ('\x7F' & *self) == '\x00'
    }
}

/// Trait for copyless casting to an ascii vector.
pub trait OwnedAsciiCast {
    /// Take ownership and cast to an ascii vector without trailing zero element.
    fn to_ascii_consume(self) -> ~[Ascii];
}

impl OwnedAsciiCast for ~[u8] {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());

        unsafe {cast::transmute(self)}
    }
}

impl OwnedAsciiCast for ~str {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        let mut s = self;
        unsafe {
            str::raw::pop_byte(&mut s);
            cast::transmute(s)
        }
    }
}

/// Trait for converting an ascii type to a string. Needed to convert `&[Ascii]` to `~str`
pub trait ToStrAscii {
    /// Convert to a string.
    fn to_str_ascii(&self) -> ~str;
}

impl<'self> ToStrAscii for &'self [Ascii] {
    #[inline(always)]
    fn to_str_ascii(&self) -> ~str {
        let mut cpy = self.to_owned();
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }
}

impl ToStrConsume for ~[Ascii] {
    #[inline(always)]
    fn to_str_consume(self) -> ~str {
        let mut cpy = self;
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }
}

// NOTE: Remove stage0 marker after snapshot
#[cfg(and(test, not(stage0)))]
mod tests {
    use super::*;
    use to_str::{ToStr,ToStrConsume};
    use str;
    use cast;

    macro_rules! v2ascii (
        ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
        (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
    )

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().to_byte(), 65u8);
        assert_eq!(65u8.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_byte(), 65u8);

        assert_eq!('A'.to_ascii().to_lower().to_char, 'a');
        assert_eq!('Z'.to_ascii().to_lower().to_char, 'z');
        assert_eq!('a'.to_ascii().to_upper().to_char, 'A');
        assert_eq!('z'.to_ascii().to_upper().to_char, 'Z');

        assert_eq!('@'.to_ascii().to_lower().to_char, '@');
        assert_eq!('['.to_ascii().to_lower().to_char, '[');
        assert_eq!('`'.to_ascii().to_upper().to_char, '`');
        assert_eq!('{'.to_ascii().to_upper().to_char, '{');
    }

    #[test]
    fn test_ascii_vec() {
        assert_eq!((&[40u8, 32u8, 59u8]).to_ascii(), v2ascii!([40, 32, 59]));
        assert_eq!("( ;".to_ascii(),                 v2ascii!([40, 32, 59]));
        // FIXME: #5475 borrowchk error, owned vectors do not live long enough
        // if chained-from directly
        let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
        let v = ~"( ;";              assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
    }

    #[test]
    fn test_owned_ascii_vec() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(~"( ;".to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~"( ;".to_ascii_consume_with_null(), v2ascii!(~[40, 32, 59, 0]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume_with_null(),
        //           v2ascii!(~[40, 32, 59, 0]));
    }

    #[test]
    fn test_ascii_to_str() { assert_eq!(v2ascii!([40, 32, 59]).to_str_ascii(), ~"( ;"); }

    #[test]
    fn test_ascii_to_str_consume() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(v2ascii!(~[40, 32, 59]).to_str_consume(), ~"( ;");
    }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_u8_slice()  { (&[127u8, 128u8, 255u8]).to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
}

<|endoftext|>


<commit_before>extern crate distrust;

use distrust::buffer::*;
use std::thread;
use std::sync::atomic::{AtomicIsize, Ordering};
use std::sync::mpsc::channel;
use std::sync::Arc;
use std::mem;

#[test]
fn should_ensure_that_length_is_a_power_of_two() {
	let size: usize = 3;
	let container = vec![Item {id: 0, payload: 0}; size].into_boxed_slice();
	let mut sequencer = new_single_thread_sequencer();
	let optional_buffer = new_ring_buffer(container, &mut sequencer);

	assert!(optional_buffer.is_none())
}

#[ignore]
#[test]
fn should_advance_sequence_number() {
	let (mut sequencer, container) = construct_params();
	let mut buffer = new_ring_buffer(container, &mut sequencer).unwrap();

	assert_eq!(buffer.get_next_sequence(), 0);
	assert_eq!(buffer.get_next_sequence(), 1);
}

#[test]
fn should_advance_published_sequence() {
	let (mut sequencer, container) = construct_params();
	let mut buffer = new_ring_buffer(container, &mut sequencer).unwrap();
	let item = Item {id: 7, payload: 11 };

	let sequence = buffer.get_next_sequence();
	buffer.publish(sequence, item);

	assert_published_sequence(&buffer, 0);
}

#[ignore]
#[test]
fn should_be_readable_from_multiple_threads() {
	let (mut sequencer, container) = construct_params();

	let mut buffer = new_ring_buffer(container, &mut sequencer).unwrap();
	let ro_buffer = &buffer;
//
//	let child = thread::spawn(move || {
//	    assert_eq!(0, ro_buffer.published_sequence());
//	});
//
//	let res = child.join();
}

struct Foo<'a> {
	sequence: &'a AtomicIsize
}

impl<'a> Foo<'a> {
	fn next_available_sequence(&self) -> isize {
		self.sequence.fetch_add(1, Ordering::Release) + 1
	}

	fn current_sequence(&self) -> isize {
		self.sequence.load(Ordering::Acquire)
	}
}

#[test]
fn should_share() {
	let boxed_1 = Box::new(AtomicIsize::new(-1));
	let raw = Box::into_raw(boxed_1);
	let mut boxed_2 : Box<AtomicIsize> = Box::new(AtomicIsize::new(0));
	let mut boxed_3 : Box<AtomicIsize> = Box::new(AtomicIsize::new(0));
	unsafe {
	boxed_2 = Box::from_raw(raw);
	boxed_3 = Box::from_raw(raw);
	}

	let foo = Foo{sequence: &boxed_2};
	assert_eq!(foo.next_available_sequence(), 0);

	let child = thread::spawn(move || {
			boxed_3.fetch_add(1, Ordering::Release);
			mem::forget(boxed_3);
    });
    let res = child.join();
    println!("res: {:?}", res);
    assert_eq!(1, foo.current_sequence());
}

#[test]
#[ignore]
fn should_have_shared_atomic() {
	let counter = Box::new(AtomicIsize::new(0));
//	let ptr = &counter;
	counter.fetch_add(1, Ordering::Release);
//
//	let child = thread::spawn(|| {
//		&counter.store(0, Ordering::Release);
//	});
//
//	while counter.load(Ordering::Acquire) != 0 {
//		// spin
//	}
//
//	let res = child.join();
//
	assert_eq!(0, counter.load(Ordering::Acquire));
}

fn assert_published_sequence(buffer: &RingBuffer<Item>, expected_sequence: i64) {
	assert_eq!(expected_sequence, buffer.get_published_sequence());
}

fn construct_params() -> (SingleThreadSequence, Box<[Item]>) {
	let size: usize = 4;
	let container = vec![Item {id: 0, payload: 0}; size].into_boxed_slice();
	let sequencer = new_single_thread_sequencer();

	(sequencer, container)
}

struct Item {
	id: i64,
	payload: i64
}

impl Clone for Item {
	fn clone(&self) -> Item {
		Item {id: self.id, payload: self.payload}
	}
}<commit_msg>test sharing methods<commit_after>extern crate distrust;

use distrust::buffer::*;
use std::thread;
use std::sync::atomic::{AtomicIsize, Ordering};
use std::sync::mpsc::channel;
use std::sync::Arc;
use std::mem;

#[test]
fn should_ensure_that_length_is_a_power_of_two() {
	let size: usize = 3;
	let container = vec![Item {id: 0, payload: 0}; size].into_boxed_slice();
	let mut sequencer = new_single_thread_sequencer();
	let optional_buffer = new_ring_buffer(container, &mut sequencer);

	assert!(optional_buffer.is_none())
}

#[ignore]
#[test]
fn should_advance_sequence_number() {
	let (mut sequencer, container) = construct_params();
	let mut buffer = new_ring_buffer(container, &mut sequencer).unwrap();

	assert_eq!(buffer.get_next_sequence(), 0);
	assert_eq!(buffer.get_next_sequence(), 1);
}

#[test]
fn should_advance_published_sequence() {
	let (mut sequencer, container) = construct_params();
	let mut buffer = new_ring_buffer(container, &mut sequencer).unwrap();
	let item = Item {id: 7, payload: 11 };

	let sequence = buffer.get_next_sequence();
	buffer.publish(sequence, item);

	assert_published_sequence(&buffer, 0);
}

#[ignore]
#[test]
fn should_be_readable_from_multiple_threads() {
	let (mut sequencer, container) = construct_params();

	let mut buffer = new_ring_buffer(container, &mut sequencer).unwrap();
	let ro_buffer = &buffer;
//
//	let child = thread::spawn(move || {
//	    assert_eq!(0, ro_buffer.published_sequence());
//	});
//
//	let res = child.join();
}

struct Foo {
	sequence: AtomicIsize
}

impl Foo {
	fn next_available_sequence(&self) -> isize {
		self.sequence.fetch_add(1, Ordering::Release) + 1
	}

	fn current_sequence(&self) -> isize {
		self.sequence.load(Ordering::Acquire)
	}
}

#[test]
fn should_share() {
	let boxed_1 = Box::new(Foo{sequence: AtomicIsize::new(-1)});
	let raw = Box::into_raw(boxed_1);
	let mut boxed_2 : Box<Foo>;
	let mut boxed_3 : Box<Foo>;
	unsafe {
	boxed_2 = Box::from_raw(raw);
	boxed_3 = Box::from_raw(raw);
	}

	assert_eq!(boxed_2.next_available_sequence(), 0);

	let child = thread::spawn(move || {
			boxed_3.next_available_sequence();
			mem::forget(boxed_3);
    });
    let res = child.join();
    println!("res: {:?}", res);
    assert_eq!(1, boxed_2.current_sequence());
}

fn assert_published_sequence(buffer: &RingBuffer<Item>, expected_sequence: i64) {
	assert_eq!(expected_sequence, buffer.get_published_sequence());
}

fn construct_params() -> (SingleThreadSequence, Box<[Item]>) {
	let size: usize = 4;
	let container = vec![Item {id: 0, payload: 0}; size].into_boxed_slice();
	let sequencer = new_single_thread_sequencer();

	(sequencer, container)
}

struct Item {
	id: i64,
	payload: i64
}

impl Clone for Item {
	fn clone(&self) -> Item {
		Item {id: self.id, payload: self.payload}
	}
}<|endoftext|>


<commit_before>#![feature(custom_test_frameworks)]
// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest.
#![test_runner(test_runner)]

use std::path::PathBuf;
use std::env;

use compiletest_rs as compiletest;
use colored::*;

fn miri_path() -> PathBuf {
    if rustc_test_suite().is_some() {
        PathBuf::from(option_env!("MIRI_PATH").unwrap())
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec<String>) {
    let in_rustc_test_suite = rustc_test_suite().is_some();
    // Add some flags we always want.
    flags.push("--edition 2018".to_owned());
    if in_rustc_test_suite {
        // Less aggressive warnings to make the rustc toolstate management less painful.
        // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.)
        flags.push("-Astable-features".to_owned());
    } else {
        flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
    }
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        flags.push(format!("--sysroot {}", sysroot));
    }

    // The rest of the configuration.
    let mut config = compiletest::Config::default().tempdir();
    config.mode = mode.parse().expect("Invalid mode");
    config.rustc_path = miri_path();
    if in_rustc_test_suite {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.filter = env::args().nth(1);
    config.host = get_host();
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.target_rustcflags = Some(flags.join(" "));
    compiletest::run_tests(&config);
}

fn compile_fail(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running compile-fail tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        // Optimizing too aggressivley makes UB detection harder, but test at least
        // the default value.
        // FIXME: Opt level 3 ICEs during stack trace generation.
        flags.push("-Zmir-opt-level=1".to_owned());
    }

    run_tests("compile-fail", path, target, flags);
}

fn miri_pass(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running run-pass tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    }

    run_tests("ui", path, target, flags);
}

fn get_host() -> String {
    let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc"));
    let rustc_version = std::process::Command::new(rustc)
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8");
    let version_meta = rustc_version::version_meta_for(&rustc_version)
        .expect("failed to parse rustc version info");
    version_meta.host
}

fn get_target() -> String {
    std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host())
}

fn run_pass_miri(opt: bool) {
    miri_pass("tests/run-pass", &get_target(), opt);
}

fn compile_fail_miri(opt: bool) {
    compile_fail("tests/compile-fail", &get_target(), opt);
}

fn test_runner(_tests: &[&()]) {
    // Add a test env var to do environment communication tests
    std::env::set_var("MIRI_ENV_VAR_TEST", "0");

    run_pass_miri(false);
    run_pass_miri(true);

    compile_fail_miri(false);
    compile_fail_miri(true);
}
<commit_msg>Auto merge of #1030 - RalfJung:mir-opt-comment, r=RalfJung<commit_after>#![feature(custom_test_frameworks)]
// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest.
#![test_runner(test_runner)]

use std::path::PathBuf;
use std::env;

use compiletest_rs as compiletest;
use colored::*;

fn miri_path() -> PathBuf {
    if rustc_test_suite().is_some() {
        PathBuf::from(option_env!("MIRI_PATH").unwrap())
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec<String>) {
    let in_rustc_test_suite = rustc_test_suite().is_some();
    // Add some flags we always want.
    flags.push("--edition 2018".to_owned());
    if in_rustc_test_suite {
        // Less aggressive warnings to make the rustc toolstate management less painful.
        // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.)
        flags.push("-Astable-features".to_owned());
    } else {
        flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
    }
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        flags.push(format!("--sysroot {}", sysroot));
    }

    // The rest of the configuration.
    let mut config = compiletest::Config::default().tempdir();
    config.mode = mode.parse().expect("Invalid mode");
    config.rustc_path = miri_path();
    if in_rustc_test_suite {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.filter = env::args().nth(1);
    config.host = get_host();
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.target_rustcflags = Some(flags.join(" "));
    compiletest::run_tests(&config);
}

fn compile_fail(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running compile-fail tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        // FIXME: Opt level 2 ICEs during stack trace generation.
        // See https://github.com/rust-lang/rust/issues/66077.
        flags.push("-Zmir-opt-level=1".to_owned());
    }

    run_tests("compile-fail", path, target, flags);
}

fn miri_pass(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running run-pass tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    }

    run_tests("ui", path, target, flags);
}

fn get_host() -> String {
    let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc"));
    let rustc_version = std::process::Command::new(rustc)
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8");
    let version_meta = rustc_version::version_meta_for(&rustc_version)
        .expect("failed to parse rustc version info");
    version_meta.host
}

fn get_target() -> String {
    std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host())
}

fn run_pass_miri(opt: bool) {
    miri_pass("tests/run-pass", &get_target(), opt);
}

fn compile_fail_miri(opt: bool) {
    compile_fail("tests/compile-fail", &get_target(), opt);
}

fn test_runner(_tests: &[&()]) {
    // Add a test env var to do environment communication tests
    std::env::set_var("MIRI_ENV_VAR_TEST", "0");

    run_pass_miri(false);
    run_pass_miri(true);

    compile_fail_miri(false);
    compile_fail_miri(true);
}
<|endoftext|>


<commit_before>extern crate whatlang;
extern crate rustc_serialize;

use whatlang::detect_lang;
use whatlang::Lang;
use whatlang::Query;

use std::fs::File;
use std::io::*;

use rustc_serialize::json;
use std::collections::HashMap;

#[test]
fn test_with_multiple_examples() {
    let file_path = "./tests/examples.json";

    let mut file = File::open(file_path).unwrap();
    let mut data = String::new();
    file.read_to_string(&mut data).unwrap();

    let examples: HashMap<String, String> = json::decode(data.as_ref()).unwrap();

    for (lang_code, text) in examples {
        print!("Test {} ... ", lang_code);

        let lang = Lang::from_code(lang_code).expect("Unknown language code");
        let query = Query::new(&text);
        let result = detect_lang(query).unwrap();
        assert_eq!(result.lang, lang);

        println!("OK");

    }
}

<commit_msg>Don't include IO in tests where possible<commit_after>extern crate whatlang;
extern crate rustc_serialize;

use whatlang::detect_lang;
use whatlang::Lang;
use whatlang::Query;

use rustc_serialize::json;
use std::collections::HashMap;

#[test]
fn test_with_multiple_examples() {
    let example_data = include_str!("examples.json");

    let examples: HashMap<String, String> = json::decode(example_data).unwrap();

    for (lang_code, text) in examples {
        print!("Test {} ... ", lang_code);

        let lang = Lang::from_code(lang_code).expect("Unknown language code");
        let query = Query::new(&text);
        let result = detect_lang(query).unwrap();
        assert_eq!(result.lang, lang);

        println!("OK");

    }
}

<|endoftext|>


<commit_before>extern crate gcc;

fn main() {
    // gcc::compile_library("libwrapper.a", &["src/wrapper.cpp"]);
    use std::process::Command;
    let incl = Command::new("llvm-config").arg("--includedir").output().unwrap();
    let incl = String::from_utf8(incl.stdout).unwrap();
    gcc::Config::new()
        .file("src/wrapper.cpp")
        .include(incl)
        .define("__STDC_CONSTANT_MACROS", None)
        .define("__STDC_LIMIT_MACROS", None)
        .flag("-std=c++11")
        .cpp(true)
        .compile("libwrapper.a");
    // gcc::compile_library("libwrapper.a", &["src/wrapper.cpp"]);
}
<commit_msg>fix build on os x<commit_after>extern crate gcc;

fn main() {
    // gcc::compile_library("libwrapper.a", &["src/wrapper.cpp"]);
    use std::process::Command;
    let incl = Command::new("llvm-config").arg("--includedir").output().unwrap();
    let mut incl = String::from_utf8(incl.stdout).unwrap();

    // drop the trailing newline
    if incl.chars().rev().next() == Some('\n') { incl.pop(); }
    gcc::Config::new()
        .file("src/wrapper.cpp")
        .include(incl)
        .define("__STDC_CONSTANT_MACROS", None)
        .define("__STDC_LIMIT_MACROS", None)
        .flag("-std=c++11")
        .cpp(true)
        .compile("libwrapper.a");
    // gcc::compile_library("libwrapper.a", &["src/wrapper.cpp"]);
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::path::Path;
use std::process::{Command, ExitStatus, Stdio};
use std::str;

#[cfg(all(feature = "backtrace", not(feature = "std")))]
compile_error! {
    "`backtrace` feature without `std` feature is not supported"
}

// This code exercises the surface area that we expect of the std Backtrace
// type. If the current toolchain is able to compile it, we go ahead and use
// backtrace in anyhow.
const PROBE: &str = r#"
    #![feature(backtrace)]
    #![allow(dead_code)]

    use std::backtrace::{Backtrace, BacktraceStatus};
    use std::error::Error;
    use std::fmt::{self, Display};

    #[derive(Debug)]
    struct E;

    impl Display for E {
        fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
            unimplemented!()
        }
    }

    impl Error for E {
        fn backtrace(&self) -> Option<&Backtrace> {
            let backtrace = Backtrace::capture();
            match backtrace.status() {
                BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {}
            }
            unimplemented!()
        }
    }
"#;

fn main() {
    if cfg!(feature = "std") {
        match compile_probe() {
            Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
            _ => {}
        }
    }

    let rustc = match rustc_minor_version() {
        Some(rustc) => rustc,
        None => return,
    };

    if rustc < 38 {
        println!("cargo:rustc-cfg=anyhow_no_macro_reexport");
    }

    if rustc < 51 {
        println!("cargo:rustc-cfg=anyhow_no_ptr_addr_of");
    }
}

fn compile_probe() -> Option<ExitStatus> {
    let rustc = env::var_os("RUSTC")?;
    let out_dir = env::var_os("OUT_DIR")?;
    let probefile = Path::new(&out_dir).join("probe.rs");
    fs::write(&probefile, PROBE).ok()?;
    Command::new(rustc)
        .stderr(Stdio::null())
        .arg("--edition=2018")
        .arg("--crate-name=anyhow_build")
        .arg("--crate-type=lib")
        .arg("--emit=metadata")
        .arg("--out-dir")
        .arg(out_dir)
        .arg(probefile)
        .status()
        .ok()
}

fn rustc_minor_version() -> Option<u32> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = str::from_utf8(&output.stdout).ok()?;
    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }
    pieces.next()?.parse().ok()
}
<commit_msg>Include Cargo rustc configuration in probe<commit_after>use std::env;
use std::fs;
use std::path::Path;
use std::process::{Command, ExitStatus, Stdio};
use std::str;

#[cfg(all(feature = "backtrace", not(feature = "std")))]
compile_error! {
    "`backtrace` feature without `std` feature is not supported"
}

// This code exercises the surface area that we expect of the std Backtrace
// type. If the current toolchain is able to compile it, we go ahead and use
// backtrace in anyhow.
const PROBE: &str = r#"
    #![feature(backtrace)]
    #![allow(dead_code)]

    use std::backtrace::{Backtrace, BacktraceStatus};
    use std::error::Error;
    use std::fmt::{self, Display};

    #[derive(Debug)]
    struct E;

    impl Display for E {
        fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
            unimplemented!()
        }
    }

    impl Error for E {
        fn backtrace(&self) -> Option<&Backtrace> {
            let backtrace = Backtrace::capture();
            match backtrace.status() {
                BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {}
            }
            unimplemented!()
        }
    }
"#;

fn main() {
    if cfg!(feature = "std") {
        match compile_probe() {
            Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
            _ => {}
        }
    }

    let rustc = match rustc_minor_version() {
        Some(rustc) => rustc,
        None => return,
    };

    if rustc < 38 {
        println!("cargo:rustc-cfg=anyhow_no_macro_reexport");
    }

    if rustc < 51 {
        println!("cargo:rustc-cfg=anyhow_no_ptr_addr_of");
    }
}

fn compile_probe() -> Option<ExitStatus> {
    let rustc = env::var_os("RUSTC")?;
    let out_dir = env::var_os("OUT_DIR")?;
    let probefile = Path::new(&out_dir).join("probe.rs");
    fs::write(&probefile, PROBE).ok()?;

    // Make sure to pick up Cargo rustc configuration.
    let mut cmd = env::var_os("CARGO_RUSTC_WRAPPER").map_or_else(
        || Command::new(&rustc),
        |wrapper| {
            let mut cmd = Command::new(wrapper);
            // The wrapper's first argument should always be the path to rustc.
            cmd.arg(&rustc);
            cmd
        },
    );

    cmd.stderr(Stdio::null())
        .arg("--edition=2018")
        .arg("--crate-name=anyhow_build")
        .arg("--crate-type=lib")
        .arg("--emit=metadata")
        .arg("--out-dir")
        .arg(out_dir)
        .arg(probefile);

    // If Cargo wants to set RUSTFLAGS, use that.
    if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") {
        if !rustflags.is_empty() {
            for arg in rustflags.split('\x1f') {
                cmd.arg(arg);
            }
        }
    }

    cmd.status().ok()
}

fn rustc_minor_version() -> Option<u32> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = str::from_utf8(&output.stdout).ok()?;
    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }
    pieces.next()?.parse().ok()
}
<|endoftext|>


<commit_before>extern crate semver;

use semver::{Version, VersionReq};
use semver::ParseError::IncorrectParse;
use std::borrow::Cow;
use std::path::PathBuf;
use std::str::from_utf8_unchecked;
use std::process::Command;

fn is_whitespace(x: &u8) -> bool {
    ['\n', '\t', ' '].contains(&(*x as char))
}

fn build_wrappers() -> (String, &'static str) {
    // Get Cargo directories
    let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
    let mut src_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
    src_dir.push("wrappers");

    // Run cmake generator
    match Command::new("cmake").arg(&src_dir).current_dir(&out_dir).status() {
        Err(e) => panic!("Failed to invoke CMake: {}", e),
        Ok(s) => {
            if !s.success() {
                panic!("CMake configuration of wrappers failed with status {}", s)
            }
        }
    }

    // Do the actual build
    match Command::new("cmake").arg("--build").arg(&out_dir).status() {
        Err(e) => panic!("Failed to invoke CMake: {}", e),
        Ok(s) => {
            if !s.success() {
                panic!("CMake build of wrappers failed with status {}", s)
            }
        }
    }

    (out_dir.into_os_string().into_string().unwrap(),
     "targetwrappers")
}

fn main() {
    let (wrappers_out_dir, wrappers_lib_name) = build_wrappers();
    println!("cargo:rustc-link-search=native={}", wrappers_out_dir);
    println!("cargo:rustc-link-lib=static={}", wrappers_lib_name);

    let minimum_llvm_version = VersionReq::parse(">=3.6").unwrap();
    let (llvm_config, version) = get_llvm_config();
    if minimum_llvm_version.matches(&version) {
        println!("Found LLVM version {}", version);
    } else {
        panic!("LLVM version 3.6 or higher is required. (Found {})", version);
    };

    // Are we using LLVM as a shared object or static library?
    let llvm_libtype = match std::env::var("CARGO_FEATURE_LLVM_DYLIB") {
        Ok(_) => "dylib",
        Err(_) => "static"
    };

    // llvm-config --ldflags: extract -L<dir> options
    let output = Command::new(&*llvm_config).arg("--ldflags").output().unwrap().stdout;
    for arg in output.split(is_whitespace) {
        if arg.starts_with(b"-L") {
            println!("cargo:rustc-link-search=native={}", unsafe {
                from_utf8_unchecked(&arg[2..])
            });
        }
    }

    // llvm-config --libs --system-libs: extract -l<lib> options
    let output = Command::new(&*llvm_config).args(&["--libs", "--system-libs"]).output().unwrap().stdout;
    for arg in output.split(is_whitespace) {
        if arg.starts_with(b"-l") {
            let arg = &arg[2..];
            let libtype = if arg.starts_with(b"LLVM") {
                llvm_libtype
            } else {
                "dylib"
            };
            println!("cargo:rustc-link-lib={}={}", libtype, unsafe {
                from_utf8_unchecked(arg)
            });
        }
    }

    // llvm-config --cxxflags: determine which libc++ to use: LLVM's or GCC's
    let output = String::from_utf8(
        Command::new(&*llvm_config).arg("--cxxflags").output().unwrap().stdout
    ).unwrap();
    let libcpp = if output.contains("stdlib=libc++") {
        "c++"
    } else {
        "stdc++"
    };
    println!("cargo:rustc-link-lib={}", libcpp);
}

fn get_llvm_config() -> (Cow<'static, str>, Version) {
    match Command::new("llvm-config").arg("--version").output() {
        Ok(x) => {
            // llvm-config was on our PATH. Easy.
            let ver = match Version::parse(&String::from_utf8_lossy(&*x.stdout)) {
                // Ignore partial error; particularly constructs like '3.8.0svn'
                // should be accepted, despite being invalid semver.
                Err(IncorrectParse(v, _)) | Ok(v) => v,
                _ => panic!("Could not determine LLVM version")
            };
            (Cow::Borrowed("llvm-config"), ver)
        }
        Err(_) => {
            panic!("llvm-config not found. Install LLVM before attempting to build.");
        }
    }
}
<commit_msg>Remove some uses of unwrap() to make failures easier to debug.<commit_after>extern crate semver;

use semver::{Version, VersionReq};
use semver::ParseError::IncorrectParse;
use std::borrow::Cow;
use std::path::PathBuf;
use std::str::from_utf8_unchecked;
use std::process::Command;

fn is_whitespace(x: &u8) -> bool {
    ['\n', '\t', ' '].contains(&(*x as char))
}

fn build_wrappers() -> (String, &'static str) {
    // Get Cargo directories
    let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
    let mut src_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
    src_dir.push("wrappers");

    // Run cmake generator
    match Command::new("cmake").arg(&src_dir).current_dir(&out_dir).status() {
        Err(e) => panic!("Failed to invoke CMake: {}", e),
        Ok(s) => {
            if !s.success() {
                panic!("CMake configuration of wrappers failed with status {}", s)
            }
        }
    }

    // Do the actual build
    match Command::new("cmake").arg("--build").arg(&out_dir).status() {
        Err(e) => panic!("Failed to invoke CMake: {}", e),
        Ok(s) => {
            if !s.success() {
                panic!("CMake build of wrappers failed with status {}", s)
            }
        }
    }

    (out_dir.into_os_string().into_string().unwrap(),
     "targetwrappers")
}

fn main() {
    let (wrappers_out_dir, wrappers_lib_name) = build_wrappers();
    println!("cargo:rustc-link-search=native={}", wrappers_out_dir);
    println!("cargo:rustc-link-lib=static={}", wrappers_lib_name);

    let minimum_llvm_version = VersionReq::parse(">=3.6").unwrap();
    let (llvm_config, version) = get_llvm_config();
    if minimum_llvm_version.matches(&version) {
        println!("Found LLVM version {}", version);
    } else {
        panic!("LLVM version 3.6 or higher is required. (Found {})", version);
    };

    // Are we using LLVM as a shared object or static library?
    let llvm_libtype = match std::env::var("CARGO_FEATURE_LLVM_DYLIB") {
        Ok(_) => "dylib",
        Err(_) => "static"
    };

    // llvm-config --ldflags: extract -L<dir> options
    let output = Command::new(&*llvm_config).arg("--ldflags")
        .output().ok().expect("Failed to get LDFLAGS from llvm-config").stdout;
    for arg in output.split(is_whitespace) {
        if arg.starts_with(b"-L") {
            println!("cargo:rustc-link-search=native={}", unsafe {
                from_utf8_unchecked(&arg[2..])
            });
        }
    }

    // llvm-config --libs --system-libs: extract -l<lib> options
    let output = Command::new(&*llvm_config).args(&["--libs", "--system-libs"])
        .output().ok().expect("Failed to get libs from llvm-config").stdout;
    for arg in output.split(is_whitespace) {
        if arg.starts_with(b"-l") {
            let arg = &arg[2..];
            let libtype = if arg.starts_with(b"LLVM") {
                llvm_libtype
            } else {
                "dylib"
            };
            println!("cargo:rustc-link-lib={}={}", libtype, unsafe {
                from_utf8_unchecked(arg)
            });
        }
    }

    // llvm-config --cxxflags: determine which libc++ to use: LLVM's or GCC's
    let output = String::from_utf8(
        Command::new(&*llvm_config).arg("--cxxflags")
            .output().ok().expect("Failed to get CXXFLAGS from llvm-config").stdout
    ).ok().expect("llvm-config --cxxflags gave invalid UTF-8");
    let libcpp = if output.contains("stdlib=libc++") {
        "c++"
    } else {
        "stdc++"
    };
    println!("cargo:rustc-link-lib={}", libcpp);
}

fn get_llvm_config() -> (Cow<'static, str>, Version) {
    match Command::new("llvm-config").arg("--version").output() {
        Ok(x) => {
            // llvm-config was on our PATH. Easy.
            let ver = match Version::parse(&String::from_utf8_lossy(&*x.stdout)) {
                // Ignore partial error; particularly constructs like '3.8.0svn'
                // should be accepted, despite being invalid semver.
                Err(IncorrectParse(v, _)) | Ok(v) => v,
                _ => panic!("Could not determine LLVM version")
            };
            (Cow::Borrowed("llvm-config"), ver)
        }
        Err(_) => {
            panic!("llvm-config not found. Install LLVM before attempting to build.");
        }
    }
}
<|endoftext|>


<commit_before>//! Details of the `metadata` section of the procedural macro.

use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::{
    braced,
    parse::{Parse, ParseStream},
    Attribute, Ident, LitBool, LitStr, Token,
};

use crate::util;

mod kw {
    syn::custom_keyword!(metadata);
    syn::custom_keyword!(description);
    syn::custom_keyword!(method);
    syn::custom_keyword!(name);
    syn::custom_keyword!(path);
    syn::custom_keyword!(rate_limited);
    syn::custom_keyword!(authentication);

    syn::custom_keyword!(None);
    syn::custom_keyword!(AccessToken);
    syn::custom_keyword!(ServerSignatures);
    syn::custom_keyword!(QueryOnlyAccessToken);
}

/// A field of Metadata that contains attribute macros
pub struct MetadataField<T> {
    /// attributes over the field
    pub attrs: Vec<Attribute>,

    /// the field itself
    pub value: T,
}

/// The result of processing the `metadata` section of the macro.
pub struct Metadata {
    /// The description field.
    pub description: LitStr,

    /// The method field.
    pub method: Ident,

    /// The name field.
    pub name: LitStr,

    /// The path field.
    pub path: LitStr,

    /// The rate_limited field.
    pub rate_limited: Vec<MetadataField<LitBool>>,

    /// The authentication field.
    pub authentication: Vec<MetadataField<AuthScheme>>,
}

fn set_field<T: ToTokens>(field: &mut Option<T>, value: T) -> syn::Result<()> {
    match field {
        Some(existing_value) => {
            let mut error = syn::Error::new_spanned(value, "duplicate field assignment");
            error.combine(syn::Error::new_spanned(existing_value, "first one here"));
            Err(error)
        }
        None => {
            *field = Some(value);
            Ok(())
        }
    }
}

impl Parse for Metadata {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let metadata_kw: kw::metadata = input.parse()?;
        let _: Token![:] = input.parse()?;

        let field_values;
        braced!(field_values in input);

        let field_values =
            field_values.parse_terminated::<FieldValue, Token![,]>(FieldValue::parse)?;

        let mut description = None;
        let mut method = None;
        let mut name = None;
        let mut path = None;
        let mut rate_limited = vec![];
        let mut authentication = vec![];

        for field_value in field_values {
            match field_value {
                FieldValue::Description(d) => set_field(&mut description, d)?,
                FieldValue::Method(m) => set_field(&mut method, m)?,
                FieldValue::Name(n) => set_field(&mut name, n)?,
                FieldValue::Path(p) => set_field(&mut path, p)?,
                FieldValue::RateLimited(value, attrs) => {
                    rate_limited.push(MetadataField { attrs, value })
                }
                FieldValue::Authentication(value, attrs) => {
                    authentication.push(MetadataField { attrs, value })
                }
            }
        }

        let missing_field =
            |name| syn::Error::new_spanned(metadata_kw, format!("missing field `{}`", name));

        Ok(Self {
            description: description.ok_or_else(|| missing_field("description"))?,
            method: method.ok_or_else(|| missing_field("method"))?,
            name: name.ok_or_else(|| missing_field("name"))?,
            path: path.ok_or_else(|| missing_field("path"))?,
            rate_limited: if rate_limited.is_empty() {
                return Err(missing_field("rate_limited"));
            } else {
                rate_limited
            },
            authentication: if authentication.is_empty() {
                return Err(missing_field("authentication"));
            } else {
                authentication
            },
        })
    }
}

#[derive(PartialEq)]
pub enum AuthScheme {
    None(kw::None),
    AccessToken(kw::AccessToken),
    ServerSignatures(kw::ServerSignatures),
    QueryOnlyAccessToken(kw::QueryOnlyAccessToken),
}

impl Parse for AuthScheme {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let lookahead = input.lookahead1();

        if lookahead.peek(kw::None) {
            input.parse().map(Self::None)
        } else if lookahead.peek(kw::AccessToken) {
            input.parse().map(Self::AccessToken)
        } else if lookahead.peek(kw::ServerSignatures) {
            input.parse().map(Self::ServerSignatures)
        } else if lookahead.peek(kw::QueryOnlyAccessToken) {
            input.parse().map(Self::QueryOnlyAccessToken)
        } else {
            Err(lookahead.error())
        }
    }
}

impl ToTokens for AuthScheme {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            AuthScheme::None(kw) => kw.to_tokens(tokens),
            AuthScheme::AccessToken(kw) => kw.to_tokens(tokens),
            AuthScheme::ServerSignatures(kw) => kw.to_tokens(tokens),
            AuthScheme::QueryOnlyAccessToken(kw) => kw.to_tokens(tokens),
        }
    }
}

enum Field {
    Description,
    Method,
    Name,
    Path,
    RateLimited,
    Authentication,
}

impl Parse for Field {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let lookahead = input.lookahead1();

        if lookahead.peek(kw::description) {
            let _: kw::description = input.parse()?;
            Ok(Self::Description)
        } else if lookahead.peek(kw::method) {
            let _: kw::method = input.parse()?;
            Ok(Self::Method)
        } else if lookahead.peek(kw::name) {
            let _: kw::name = input.parse()?;
            Ok(Self::Name)
        } else if lookahead.peek(kw::path) {
            let _: kw::path = input.parse()?;
            Ok(Self::Path)
        } else if lookahead.peek(kw::rate_limited) {
            let _: kw::rate_limited = input.parse()?;
            Ok(Self::RateLimited)
        } else if lookahead.peek(kw::authentication) {
            let _: kw::authentication = input.parse()?;
            Ok(Self::Authentication)
        } else {
            Err(lookahead.error())
        }
    }
}

enum FieldValue {
    Description(LitStr),
    Method(Ident),
    Name(LitStr),
    Path(LitStr),
    RateLimited(LitBool, Vec<Attribute>),
    Authentication(AuthScheme, Vec<Attribute>),
}

impl Parse for FieldValue {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let attrs: Vec<Attribute> = input.call(Attribute::parse_outer)?;
        for attr in attrs.iter() {
            if !util::is_cfg_attribute(attr) {
                return Err(syn::Error::new_spanned(
                    &attr,
                    "only `cfg` attributes may appear here",
                ));
            }
        }
        let field: Field = input.parse()?;
        let _: Token![:] = input.parse()?;

        Ok(match field {
            Field::Description => Self::Description(input.parse()?),
            Field::Method => Self::Method(input.parse()?),
            Field::Name => Self::Name(input.parse()?),
            Field::Path => {
                let path: LitStr = input.parse()?;

                if !util::is_valid_endpoint_path(&path.value()) {
                    return Err(syn::Error::new_spanned(
                        &path,
                        "path may only contain printable ASCII characters with no spaces",
                    ));
                }

                Self::Path(path)
            }
            Field::RateLimited => Self::RateLimited(input.parse()?, attrs),
            Field::Authentication => Self::Authentication(input.parse()?, attrs),
        })
    }
}
<commit_msg>api: Add missing anonymous lifetime<commit_after>//! Details of the `metadata` section of the procedural macro.

use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::{
    braced,
    parse::{Parse, ParseStream},
    Attribute, Ident, LitBool, LitStr, Token,
};

use crate::util;

mod kw {
    syn::custom_keyword!(metadata);
    syn::custom_keyword!(description);
    syn::custom_keyword!(method);
    syn::custom_keyword!(name);
    syn::custom_keyword!(path);
    syn::custom_keyword!(rate_limited);
    syn::custom_keyword!(authentication);

    syn::custom_keyword!(None);
    syn::custom_keyword!(AccessToken);
    syn::custom_keyword!(ServerSignatures);
    syn::custom_keyword!(QueryOnlyAccessToken);
}

/// A field of Metadata that contains attribute macros
pub struct MetadataField<T> {
    /// attributes over the field
    pub attrs: Vec<Attribute>,

    /// the field itself
    pub value: T,
}

/// The result of processing the `metadata` section of the macro.
pub struct Metadata {
    /// The description field.
    pub description: LitStr,

    /// The method field.
    pub method: Ident,

    /// The name field.
    pub name: LitStr,

    /// The path field.
    pub path: LitStr,

    /// The rate_limited field.
    pub rate_limited: Vec<MetadataField<LitBool>>,

    /// The authentication field.
    pub authentication: Vec<MetadataField<AuthScheme>>,
}

fn set_field<T: ToTokens>(field: &mut Option<T>, value: T) -> syn::Result<()> {
    match field {
        Some(existing_value) => {
            let mut error = syn::Error::new_spanned(value, "duplicate field assignment");
            error.combine(syn::Error::new_spanned(existing_value, "first one here"));
            Err(error)
        }
        None => {
            *field = Some(value);
            Ok(())
        }
    }
}

impl Parse for Metadata {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let metadata_kw: kw::metadata = input.parse()?;
        let _: Token![:] = input.parse()?;

        let field_values;
        braced!(field_values in input);

        let field_values =
            field_values.parse_terminated::<FieldValue, Token![,]>(FieldValue::parse)?;

        let mut description = None;
        let mut method = None;
        let mut name = None;
        let mut path = None;
        let mut rate_limited = vec![];
        let mut authentication = vec![];

        for field_value in field_values {
            match field_value {
                FieldValue::Description(d) => set_field(&mut description, d)?,
                FieldValue::Method(m) => set_field(&mut method, m)?,
                FieldValue::Name(n) => set_field(&mut name, n)?,
                FieldValue::Path(p) => set_field(&mut path, p)?,
                FieldValue::RateLimited(value, attrs) => {
                    rate_limited.push(MetadataField { attrs, value })
                }
                FieldValue::Authentication(value, attrs) => {
                    authentication.push(MetadataField { attrs, value })
                }
            }
        }

        let missing_field =
            |name| syn::Error::new_spanned(metadata_kw, format!("missing field `{}`", name));

        Ok(Self {
            description: description.ok_or_else(|| missing_field("description"))?,
            method: method.ok_or_else(|| missing_field("method"))?,
            name: name.ok_or_else(|| missing_field("name"))?,
            path: path.ok_or_else(|| missing_field("path"))?,
            rate_limited: if rate_limited.is_empty() {
                return Err(missing_field("rate_limited"));
            } else {
                rate_limited
            },
            authentication: if authentication.is_empty() {
                return Err(missing_field("authentication"));
            } else {
                authentication
            },
        })
    }
}

#[derive(PartialEq)]
pub enum AuthScheme {
    None(kw::None),
    AccessToken(kw::AccessToken),
    ServerSignatures(kw::ServerSignatures),
    QueryOnlyAccessToken(kw::QueryOnlyAccessToken),
}

impl Parse for AuthScheme {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let lookahead = input.lookahead1();

        if lookahead.peek(kw::None) {
            input.parse().map(Self::None)
        } else if lookahead.peek(kw::AccessToken) {
            input.parse().map(Self::AccessToken)
        } else if lookahead.peek(kw::ServerSignatures) {
            input.parse().map(Self::ServerSignatures)
        } else if lookahead.peek(kw::QueryOnlyAccessToken) {
            input.parse().map(Self::QueryOnlyAccessToken)
        } else {
            Err(lookahead.error())
        }
    }
}

impl ToTokens for AuthScheme {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            AuthScheme::None(kw) => kw.to_tokens(tokens),
            AuthScheme::AccessToken(kw) => kw.to_tokens(tokens),
            AuthScheme::ServerSignatures(kw) => kw.to_tokens(tokens),
            AuthScheme::QueryOnlyAccessToken(kw) => kw.to_tokens(tokens),
        }
    }
}

enum Field {
    Description,
    Method,
    Name,
    Path,
    RateLimited,
    Authentication,
}

impl Parse for Field {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let lookahead = input.lookahead1();

        if lookahead.peek(kw::description) {
            let _: kw::description = input.parse()?;
            Ok(Self::Description)
        } else if lookahead.peek(kw::method) {
            let _: kw::method = input.parse()?;
            Ok(Self::Method)
        } else if lookahead.peek(kw::name) {
            let _: kw::name = input.parse()?;
            Ok(Self::Name)
        } else if lookahead.peek(kw::path) {
            let _: kw::path = input.parse()?;
            Ok(Self::Path)
        } else if lookahead.peek(kw::rate_limited) {
            let _: kw::rate_limited = input.parse()?;
            Ok(Self::RateLimited)
        } else if lookahead.peek(kw::authentication) {
            let _: kw::authentication = input.parse()?;
            Ok(Self::Authentication)
        } else {
            Err(lookahead.error())
        }
    }
}

enum FieldValue {
    Description(LitStr),
    Method(Ident),
    Name(LitStr),
    Path(LitStr),
    RateLimited(LitBool, Vec<Attribute>),
    Authentication(AuthScheme, Vec<Attribute>),
}

impl Parse for FieldValue {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let attrs: Vec<Attribute> = input.call(Attribute::parse_outer)?;
        for attr in attrs.iter() {
            if !util::is_cfg_attribute(attr) {
                return Err(syn::Error::new_spanned(
                    &attr,
                    "only `cfg` attributes may appear here",
                ));
            }
        }
        let field: Field = input.parse()?;
        let _: Token![:] = input.parse()?;

        Ok(match field {
            Field::Description => Self::Description(input.parse()?),
            Field::Method => Self::Method(input.parse()?),
            Field::Name => Self::Name(input.parse()?),
            Field::Path => {
                let path: LitStr = input.parse()?;

                if !util::is_valid_endpoint_path(&path.value()) {
                    return Err(syn::Error::new_spanned(
                        &path,
                        "path may only contain printable ASCII characters with no spaces",
                    ));
                }

                Self::Path(path)
            }
            Field::RateLimited => Self::RateLimited(input.parse()?, attrs),
            Field::Authentication => Self::Authentication(input.parse()?, attrs),
        })
    }
}
<|endoftext|>


<commit_before>// Test impls

impl<T> JSTraceable for SmallVec<[T; 1]> {}

impl<K, V, NodeRef: Deref<Target = Node<K, V>>> Handle<NodeRef, handle::Edge, handle::Internal> {
    // Keep this.
}

impl<V> Test<V>
where
    V: Clone, // This comment is NOT removed by formating!
{
    pub fn new(value: V) -> Self {
        Test {
            cloned_value: value.clone(),
            value: value,
        }
    }
}

impl X<T> /* comment */ {}
impl Y<T> // comment
{
}

impl<T> Foo for T
// comment1
where
    // comment2
    // blah
    T: Clone,
{
}

// #1823
default impl Trait for X {}
default unsafe impl Trait for Y {}
pub default unsafe impl Trait for Z {}
<commit_msg>Add a test for #2212<commit_after>// Test impls

impl<T> JSTraceable for SmallVec<[T; 1]> {}

impl<K, V, NodeRef: Deref<Target = Node<K, V>>> Handle<NodeRef, handle::Edge, handle::Internal> {
    // Keep this.
}

impl<V> Test<V>
where
    V: Clone, // This comment is NOT removed by formating!
{
    pub fn new(value: V) -> Self {
        Test {
            cloned_value: value.clone(),
            value: value,
        }
    }
}

impl X<T> /* comment */ {}
impl Y<T> // comment
{
}

impl<T> Foo for T
// comment1
where
    // comment2
    // blah
    T: Clone,
{
}

// #1823
default impl Trait for X {}
default unsafe impl Trait for Y {}
pub default unsafe impl Trait for Z {}

// #2212
impl ConstWithDefault {
    default const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
}
<|endoftext|>


<commit_before>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate compiletest_rs as compiletest;

use std::env;

fn run_mode(mode: &'static str) {
    let mut config = compiletest::Config::default();

    config.mode = mode.parse().expect("invalid mode");
    config.target_rustcflags = Some("-L tests/deps/target/debug/deps".to_owned());
    if let Ok(name) = env::var("TESTNAME") {
        config.filter = Some(name);
    }
    config.src_base = format!("tests/{}", mode).into();

    compiletest::run_tests(&config);
}

#[test]
fn ui() {
    run_mode("ui");
}
<commit_msg>Simplify compiletest setup<commit_after>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate compiletest_rs as compiletest;

#[test]
fn ui() {
    compiletest::run_tests(&compiletest::Config {
        mode: compiletest::common::Mode::Ui,
        src_base: std::path::PathBuf::from("tests/ui"),
        target_rustcflags: Some(String::from("-L tests/deps/target/debug/deps")),
        ..Default::default()
    });
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use glib;
use glib::prelude::*;
use glib::subclass;
use glib::subclass::prelude::*;
use gst;
use gst::prelude::*;
use gst::subclass::prelude::*;

// Struct containing all the element data
struct ProgressBin {
    progress: gst::Element,
    srcpad: gst::GhostPad,
    sinkpad: gst::GhostPad,
}

// This trait registers our type with the GObject object system and
// provides the entry points for creating a new instance and setting
// up the class data
impl ObjectSubclass for ProgressBin {
    const NAME: &'static str = "RsProgressBin";
    type ParentType = gst::Bin;
    type Instance = gst::subclass::ElementInstanceStruct<Self>;
    type Class = subclass::simple::ClassStruct<Self>;

    // This macro provides some boilerplate.
    glib_object_subclass!();

    // Called when a new instance is to be created. We need to return an instance
    // of our struct here and also get the class struct passed in case it's needed
    fn new_with_class(klass: &subclass::simple::ClassStruct<Self>) -> Self {
        // Create our two ghostpads from the templates that were registered with
        // the class. We don't provide a target for them yet because we can only
        // do so after the progressreport element was added to the bin.
        //
        // We do that and adding the pads inside glib::Object::constructed() later.
        let templ = klass.get_pad_template("sink").unwrap();
        let sinkpad = gst::GhostPad::new_no_target_from_template(Some("sink"), &templ).unwrap();
        let templ = klass.get_pad_template("src").unwrap();
        let srcpad = gst::GhostPad::new_no_target_from_template(Some("src"), &templ).unwrap();

        // Create the progressreport element.
        let progress = gst::ElementFactory::make("progressreport", Some("progress")).unwrap();
        // Don't let progressreport print to stdout itself
        progress.set_property("silent", &true).unwrap();

        // Return an instance of our struct
        Self {
            progress,
            srcpad,
            sinkpad,
        }
    }

    // Called exactly once when registering the type. Used for
    // setting up metadata for all instances, e.g. the name and
    // classification and the pad templates with their caps.
    //
    // Actual instances can create pads based on those pad templates
    // with a subset of the caps given here.
    fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
        // Set the element specific metadata. This information is what
        // is visible from gst-inspect-1.0 and can also be programatically
        // retrieved from the gst::Registry after initial registration
        // without having to load the plugin in memory.
        klass.set_metadata(
            "ProgressBin",
            "Generic",
            "Prints progress information to stdout",
            "Sebastian Dröge <sebastian@centricular.com>",
        );

        // Create and add pad templates for our sink and source pad. These
        // are later used for actually creating the pads and beforehand
        // already provide information to GStreamer about all possible
        // pads that could exist for this type.

        // Our element can accept any possible caps on both pads
        let caps = gst::Caps::new_any();
        let src_pad_template = gst::PadTemplate::new(
            "src",
            gst::PadDirection::Src,
            gst::PadPresence::Always,
            &caps,
        )
        .unwrap();
        klass.add_pad_template(src_pad_template);

        let sink_pad_template = gst::PadTemplate::new(
            "sink",
            gst::PadDirection::Sink,
            gst::PadPresence::Always,
            &caps,
        )
        .unwrap();
        klass.add_pad_template(sink_pad_template);
    }
}

// Implementation of glib::Object virtual methods
impl ObjectImpl for ProgressBin {
    // This macro provides some boilerplate
    glib_object_impl!();

    // Called right after construction of a new instance
    fn constructed(&self, obj: &glib::Object) {
        // Call the parent class' ::constructed() implementation first
        self.parent_constructed(obj);

        // Here we actually add the pads we created in ProgressBin::new() to the
        // element so that GStreamer is aware of their existence.
        let bin = obj.downcast_ref::<gst::Bin>().unwrap();

        // Add the progressreport element to the bin.
        bin.add(&self.progress).unwrap();

        // Then set the ghost pad targets to the corresponding pads of the progressreport element.
        self.sinkpad
            .set_target(Some(&self.progress.get_static_pad("sink").unwrap()))
            .unwrap();
        self.srcpad
            .set_target(Some(&self.progress.get_static_pad("src").unwrap()))
            .unwrap();

        // And finally add the two ghostpads to the bin.
        bin.add_pad(&self.sinkpad).unwrap();
        bin.add_pad(&self.srcpad).unwrap();
    }
}

// Implementation of gst::Element virtual methods
impl ElementImpl for ProgressBin {}

// Implementation of gst::Bin virtual methods
impl BinImpl for ProgressBin {
    fn handle_message(&self, bin: &gst::Bin, msg: gst::Message) {
        use gst::MessageView;

        match msg.view() {
            // If this is the progressreport message, we print the status
            // to stdout. Otherwise we pass through to the default message
            // handling of the parent class, i.e. forwarding to the parent
            // bins and the application.
            MessageView::Element(ref msg)
                if msg.get_src().as_ref() == Some(self.progress.upcast_ref())
                    && msg
                        .get_structure()
                        .map(|s| s.get_name() == "progress")
                        .unwrap_or(false) =>
            {
                let s = msg.get_structure().unwrap();
                let percent = s
                    .get_some::<f64>("percent-double")
                    .expect("ProgressBin::handle_message");

                println!("progress: {:5.1}%", percent);
            }
            _ => self.parent_handle_message(bin, msg),
        }
    }
}

// Registers the type for our element, and then registers in GStreamer under
// the name "rsprogressbin" for being able to instantiate it via e.g.
// gst::ElementFactory::make().
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
    gst::Element::register(
        Some(plugin),
        "rsprogressbin",
        gst::Rank::None,
        ProgressBin::get_type(),
    )
}
<commit_msg>tutorial/progressbin: Handle streams without duration correctly<commit_after>// Copyright (C) 2019 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use glib;
use glib::prelude::*;
use glib::subclass;
use glib::subclass::prelude::*;
use gst;
use gst::prelude::*;
use gst::subclass::prelude::*;

// Struct containing all the element data
struct ProgressBin {
    progress: gst::Element,
    srcpad: gst::GhostPad,
    sinkpad: gst::GhostPad,
}

// This trait registers our type with the GObject object system and
// provides the entry points for creating a new instance and setting
// up the class data
impl ObjectSubclass for ProgressBin {
    const NAME: &'static str = "RsProgressBin";
    type ParentType = gst::Bin;
    type Instance = gst::subclass::ElementInstanceStruct<Self>;
    type Class = subclass::simple::ClassStruct<Self>;

    // This macro provides some boilerplate.
    glib_object_subclass!();

    // Called when a new instance is to be created. We need to return an instance
    // of our struct here and also get the class struct passed in case it's needed
    fn new_with_class(klass: &subclass::simple::ClassStruct<Self>) -> Self {
        // Create our two ghostpads from the templates that were registered with
        // the class. We don't provide a target for them yet because we can only
        // do so after the progressreport element was added to the bin.
        //
        // We do that and adding the pads inside glib::Object::constructed() later.
        let templ = klass.get_pad_template("sink").unwrap();
        let sinkpad = gst::GhostPad::new_no_target_from_template(Some("sink"), &templ).unwrap();
        let templ = klass.get_pad_template("src").unwrap();
        let srcpad = gst::GhostPad::new_no_target_from_template(Some("src"), &templ).unwrap();

        // Create the progressreport element.
        let progress = gst::ElementFactory::make("progressreport", Some("progress")).unwrap();
        // Don't let progressreport print to stdout itself
        progress.set_property("silent", &true).unwrap();

        // Return an instance of our struct
        Self {
            progress,
            srcpad,
            sinkpad,
        }
    }

    // Called exactly once when registering the type. Used for
    // setting up metadata for all instances, e.g. the name and
    // classification and the pad templates with their caps.
    //
    // Actual instances can create pads based on those pad templates
    // with a subset of the caps given here.
    fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
        // Set the element specific metadata. This information is what
        // is visible from gst-inspect-1.0 and can also be programatically
        // retrieved from the gst::Registry after initial registration
        // without having to load the plugin in memory.
        klass.set_metadata(
            "ProgressBin",
            "Generic",
            "Prints progress information to stdout",
            "Sebastian Dröge <sebastian@centricular.com>",
        );

        // Create and add pad templates for our sink and source pad. These
        // are later used for actually creating the pads and beforehand
        // already provide information to GStreamer about all possible
        // pads that could exist for this type.

        // Our element can accept any possible caps on both pads
        let caps = gst::Caps::new_any();
        let src_pad_template = gst::PadTemplate::new(
            "src",
            gst::PadDirection::Src,
            gst::PadPresence::Always,
            &caps,
        )
        .unwrap();
        klass.add_pad_template(src_pad_template);

        let sink_pad_template = gst::PadTemplate::new(
            "sink",
            gst::PadDirection::Sink,
            gst::PadPresence::Always,
            &caps,
        )
        .unwrap();
        klass.add_pad_template(sink_pad_template);
    }
}

// Implementation of glib::Object virtual methods
impl ObjectImpl for ProgressBin {
    // This macro provides some boilerplate
    glib_object_impl!();

    // Called right after construction of a new instance
    fn constructed(&self, obj: &glib::Object) {
        // Call the parent class' ::constructed() implementation first
        self.parent_constructed(obj);

        // Here we actually add the pads we created in ProgressBin::new() to the
        // element so that GStreamer is aware of their existence.
        let bin = obj.downcast_ref::<gst::Bin>().unwrap();

        // Add the progressreport element to the bin.
        bin.add(&self.progress).unwrap();

        // Then set the ghost pad targets to the corresponding pads of the progressreport element.
        self.sinkpad
            .set_target(Some(&self.progress.get_static_pad("sink").unwrap()))
            .unwrap();
        self.srcpad
            .set_target(Some(&self.progress.get_static_pad("src").unwrap()))
            .unwrap();

        // And finally add the two ghostpads to the bin.
        bin.add_pad(&self.sinkpad).unwrap();
        bin.add_pad(&self.srcpad).unwrap();
    }
}

// Implementation of gst::Element virtual methods
impl ElementImpl for ProgressBin {}

// Implementation of gst::Bin virtual methods
impl BinImpl for ProgressBin {
    fn handle_message(&self, bin: &gst::Bin, msg: gst::Message) {
        use gst::MessageView;

        match msg.view() {
            // If this is the progressreport message, we print the status
            // to stdout. Otherwise we pass through to the default message
            // handling of the parent class, i.e. forwarding to the parent
            // bins and the application.
            MessageView::Element(ref msg)
                if msg.get_src().as_ref() == Some(self.progress.upcast_ref())
                    && msg
                        .get_structure()
                        .map(|s| s.get_name() == "progress")
                        .unwrap_or(false) =>
            {
                let s = msg.get_structure().unwrap();
                if let Ok(percent) = s.get_some::<f64>("percent-double") {
                    println!("progress: {:5.1}%", percent);
                }
            }
            _ => self.parent_handle_message(bin, msg),
        }
    }
}

// Registers the type for our element, and then registers in GStreamer under
// the name "rsprogressbin" for being able to instantiate it via e.g.
// gst::ElementFactory::make().
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
    gst::Element::register(
        Some(plugin),
        "rsprogressbin",
        gst::Rank::None,
        ProgressBin::get_type(),
    )
}
<|endoftext|>


<commit_before>use super::super::{Y, X, Grid};
use super::*;

/// Type for status of frontier.
///
/// - -1: Closed end
/// - 0, 1, ...: Open endpoint (the another end is also in the frontier)
///   The another end may be the endpoint itself.
/// - -2, -3, ...: Open endpoint (the another end is connected to a number cell)
type Frontier = Vec<i32>;
const CLOSED_END: i32 = -1;

pub fn solve(problem: &Grid<Clue>) -> Vec<LinePlacement> {
    let height = problem.height();
    let width = problem.width();
    let mut internal_problem = Grid::new(height, width, 0);
    for y in 0..height {
        for x in 0..width {
            let Clue(c) = problem[(Y(y), X(x))];
            if c > 0 {
                internal_problem[(Y(y), X(x))] = -c - 1;
            }
        }
    }

    let mut initial_frontier = vec![CLOSED_END; width as usize];
    for x in 0..width {
        initial_frontier[x as usize] = if problem[(Y(0), X(x))] == Clue(0) { x } else { internal_problem[(Y(0), X(x))] };
    }
    let mut place = LinePlacement::new(height, width);
    let mut answers = vec![];
    search(0, 0, &internal_problem, &initial_frontier, &mut place, &mut answers);

    answers
}

fn search(y: i32, x: i32, problem: &Grid<i32>, frontier: &Frontier, place: &mut LinePlacement, answers: &mut Vec<LinePlacement>) {
    let (y, x) = if x == problem.width() { (y + 1, 0) } else { (y, x) };
    if y == problem.height() {
        answers.push(place.clone());
        return;
    }

    for &(h, v) in &[(false, false), (false, true), (true, false), (true, true)] {
        if v && y == problem.height() - 1 { continue; }
        if h && x == problem.width() - 1 { continue; }

        let deg =
            if v { 1 } else { 0 } +
            if h { 1 } else { 0 } +
            if place.down((Y(y - 1), X(x))) { 1 } else { 0 } +
            if place.right((Y(y), X(x - 1))) { 1 } else { 0 } +
            if problem[(Y(y), X(x))] < 0 { 1 } else { 0 };
        if deg != 0 && deg != 2 { continue; }

        let mut new_frontier = frontier.clone();

        // Forbidden patterns related to isolated cells:
        //
        // + X ; X +
        // |   ;   |
        // +-+ ; +-+
        if h && y > 0 && x < problem.width() - 1 {
            if place.isolated((Y(y - 1), X(x + 1))) && place.down((Y(y - 1), X(x))) { continue; }
            if place.isolated((Y(y - 1), X(x))) && place.down((Y(y - 1), X(x + 1))) { continue; }
        }

        // Forbidden patterns related to redundant paths:
        //
        // +-+ ; +-+ ; + + ; +-+
        // |   ;   | ; | | ; | |
        // +-+ ; +-+ ; +-+ ; + +
        if h && y > 0 && x < problem.width() - 1 {
            if place.right((Y(y - 1), X(x))) && (place.down((Y(y - 1), X(x))) || place.down((Y(y - 1), X(x + 1)))) { continue; }
            if place.down((Y(y - 1), X(x))) && place.down((Y(y - 1), X(x + 1))) { continue; }
        }
        if v && x > 0 {
            if place.right((Y(y), X(x - 1))) && place.down((Y(y), X(x - 1))) { continue; }
        }

        if h {
            if join(&mut new_frontier, x, x + 1) { continue; }
        }

        if v {
            let below_cell = problem[(Y(y + 1), X(x))];
            if below_cell < 0 && connect_to_number(&mut new_frontier, x, below_cell) { continue; }
        } else {
            if forget(&mut new_frontier, x) { continue; }

            if y < problem.height() - 1 {
                let below_cell = problem[(Y(y + 1), X(x))];
                if below_cell < 0 {
                    new_frontier[x as usize] = below_cell;
                } else {
                    new_frontier[x as usize] = x;
                }
            }
        }

        if h { place.set_right((Y(y), X(x)), true); }
        if v { place.set_down((Y(y), X(x)), true); }

        search(y, x + 1, problem, &new_frontier, place, answers);

        if h { place.set_right((Y(y), X(x)), false); }
        if v { place.set_down((Y(y), X(x)), false); }
    }
}

/// Connect two open endpoints `i` and `j` in `frontier`.
/// Returns `true` iff this operation results in inconsistency.
fn join(frontier: &mut Frontier, i: i32, j: i32) -> bool {
    let i = i as usize;
    let j = j as usize;

    // Both endpoints must be open
    if frontier[i] == CLOSED_END || frontier[j] == CLOSED_END {
        return true;
    }

    let i_another = frontier[i];
    let j_another = frontier[j];
    frontier[i] = CLOSED_END;
    frontier[j] = CLOSED_END;

    match (i_another < 0, j_another < 0) {
        (true, true) => {
            if i_another != j_another {
                return true;
            }
        },
        (true, false) => frontier[j_another as usize] = i_another,
        (false, true) => frontier[i_another as usize] = j_another,
        (false, false) => {
            // Loops are not allowed
            if i_another as usize == j {
                return true;
            }
            frontier[i_another as usize] = j_another;
            frontier[j_another as usize] = i_another;
        }
    }
    false
}

/// Forget closed or isolated endpoint `i` in `frontier`.
/// Returns `true` iff this operation results in inconsistency.
fn forget(frontier: &mut Frontier, i: i32) -> bool {
    frontier[i as usize] != CLOSED_END && frontier[i as usize] != i
}

/// Connect endpoint `i` in `frontier` to a number cell with value `num` directly.
/// Returns `true` iff this operation results in inconsistency.
fn connect_to_number(frontier: &mut Frontier, i: i32, num: i32) -> bool {
    let i = i as usize;
    let another = frontier[i];
    if another == CLOSED_END {
        return true;
    }
    frontier[i] = CLOSED_END;

    if another < 0 {
        num != another
    } else {
        frontier[another as usize] = num;
        false
    }
}

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

    fn run_problem_test(input: &[&str]) {
        let height = (input.len() / 2 + 1) as i32;
        let width = (input[0].len() / 2 + 1) as i32;

        let mut problem = Grid::new(height, width, NO_CLUE);
        for y in 0..height {
            let mut row_iter = input[(y * 2) as usize].chars();

            for x in 0..width {
                if x > 0 { row_iter.next(); }
                let c = row_iter.next().unwrap();
                if '1' <= c && c <= '9' {
                    problem[(Y(y), X(x))] = Clue(((c as u8) - ('0' as u8)) as i32);
                }
            }
        }

        let ans = solve(&problem);
        assert_eq!(ans.len(), 1);

        let ans = &ans[0];

        for y in 0..(2 * height - 1) {
            let mut row_iter = input[y as usize].chars();

            for x in 0..(2 * width - 1) {
                let c = row_iter.next().unwrap();
                if y % 2 == 1 && x % 2 == 0 {
                    assert_eq!(ans.down((Y(y / 2), X(x / 2))), c == '|');
                } else if y % 2 == 0 && x % 2 == 1 {
                    assert_eq!(ans.right((Y(y / 2), X(x / 2))), c == '-', "{} {}", y, x);
                }
            }
        }
    }

    #[test]
    fn test_solver() {
        run_problem_test(&[
            "+-2 4-+-+",
            "|       |",
            "+ 1-+-1 4",
            "|        ",
            "+ 3 2-+-+",
            "| |     |",
            "+ +-+-3 +",
            "|       |",
            "+-+-+-+-+",
        ]);
    }
}
<commit_msg>Numberlink: add more pruning<commit_after>use super::super::{Y, X, Grid};
use super::*;

/// Type for status of frontier.
///
/// - -1: Closed end
/// - 0, 1, ...: Open endpoint (the another end is also in the frontier)
///   The another end may be the endpoint itself.
/// - -2, -3, ...: Open endpoint (the another end is connected to a number cell)
type Frontier = Vec<i32>;
const CLOSED_END: i32 = -1;

pub fn solve(problem: &Grid<Clue>) -> Vec<LinePlacement> {
    let height = problem.height();
    let width = problem.width();
    let mut internal_problem = Grid::new(height, width, 0);
    for y in 0..height {
        for x in 0..width {
            let Clue(c) = problem[(Y(y), X(x))];
            if c > 0 {
                internal_problem[(Y(y), X(x))] = -c - 1;
            }
        }
    }

    let mut initial_frontier = vec![CLOSED_END; width as usize];
    for x in 0..width {
        initial_frontier[x as usize] = if problem[(Y(0), X(x))] == Clue(0) { x } else { internal_problem[(Y(0), X(x))] };
    }
    let mut place = LinePlacement::new(height, width);
    let mut answers = vec![];
    search(0, 0, &internal_problem, &initial_frontier, &mut place, &mut answers);

    answers
}

fn search(y: i32, x: i32, problem: &Grid<i32>, frontier: &Frontier, place: &mut LinePlacement, answers: &mut Vec<LinePlacement>) {
    let (y, x) = if x == problem.width() { (y + 1, 0) } else { (y, x) };
    if y == problem.height() {
        answers.push(place.clone());
        return;
    }

    for &(h, v) in &[(false, false), (false, true), (true, false), (true, true)] {
        if v && y == problem.height() - 1 { continue; }
        if h && x == problem.width() - 1 { continue; }

        let deg =
            if v { 1 } else { 0 } +
            if h { 1 } else { 0 } +
            if place.down((Y(y - 1), X(x))) { 1 } else { 0 } +
            if place.right((Y(y), X(x - 1))) { 1 } else { 0 } +
            if problem[(Y(y), X(x))] < 0 { 1 } else { 0 };
        if deg != 0 && deg != 2 { continue; }

        let mut new_frontier = frontier.clone();

        // Forbidden patterns related to isolated cells:
        //
        // + X ; X +
        // |   ;   |
        // +-+ ; +-+
        if h && y > 0 && x < problem.width() - 1 {
            if place.isolated((Y(y - 1), X(x + 1))) && place.down((Y(y - 1), X(x))) { continue; }
            if place.isolated((Y(y - 1), X(x))) && place.down((Y(y - 1), X(x + 1))) { continue; }
        }

        // Forbidden patterns related to redundant paths:
        //
        // +-+ ; +-+ ; + + ; +-+
        // |   ;   | ; | | ; | |
        // +-+ ; +-+ ; +-+ ; + +
        if h && y > 0 && x < problem.width() - 1 {
            if place.right((Y(y - 1), X(x))) && (place.down((Y(y - 1), X(x))) || place.down((Y(y - 1), X(x + 1)))) { continue; }
            if place.down((Y(y - 1), X(x))) && place.down((Y(y - 1), X(x + 1))) { continue; }
        }
        if v && x > 0 {
            if place.right((Y(y), X(x - 1))) && place.down((Y(y), X(x - 1))) { continue; }
        }
        // +-+ ... +-+
        // |         |
        // + + ... + +
        if y > 0 && place.down((Y(y - 1), X(x))) {
            let mut w = 0;
            while x - 1 - w >= 0 && place.right((Y(y - 1), X(x - 1 - w))) {
                w += 1;
            }
            if w > 0 && place.down((Y(y - 1), X(x - w))) {
                let mut invalid = true;
                for x2 in (x - w)..x {
                    if place.right((Y(y), X(x2))) || (x2 != x && problem[(Y(y), X(x2))] < 0) {
                        invalid = false;
                        break;
                    }
                }
                if invalid {
                    continue;
                }
            }
        }

        if h {
            if join(&mut new_frontier, x, x + 1) { continue; }
        }

        if v {
            let below_cell = problem[(Y(y + 1), X(x))];
            if below_cell < 0 && connect_to_number(&mut new_frontier, x, below_cell) { continue; }
        } else {
            if forget(&mut new_frontier, x) { continue; }

            if y < problem.height() - 1 {
                let below_cell = problem[(Y(y + 1), X(x))];
                if below_cell < 0 {
                    new_frontier[x as usize] = below_cell;
                } else {
                    new_frontier[x as usize] = x;
                }
            }
        }

        if h { place.set_right((Y(y), X(x)), true); }
        if v { place.set_down((Y(y), X(x)), true); }

        search(y, x + 1, problem, &new_frontier, place, answers);

        if h { place.set_right((Y(y), X(x)), false); }
        if v { place.set_down((Y(y), X(x)), false); }
    }
}

/// Connect two open endpoints `i` and `j` in `frontier`.
/// Returns `true` iff this operation results in inconsistency.
fn join(frontier: &mut Frontier, i: i32, j: i32) -> bool {
    let i = i as usize;
    let j = j as usize;

    // Both endpoints must be open
    if frontier[i] == CLOSED_END || frontier[j] == CLOSED_END {
        return true;
    }

    let i_another = frontier[i];
    let j_another = frontier[j];
    frontier[i] = CLOSED_END;
    frontier[j] = CLOSED_END;

    match (i_another < 0, j_another < 0) {
        (true, true) => {
            if i_another != j_another {
                return true;
            }
        },
        (true, false) => frontier[j_another as usize] = i_another,
        (false, true) => frontier[i_another as usize] = j_another,
        (false, false) => {
            // Loops are not allowed
            if i_another as usize == j {
                return true;
            }
            frontier[i_another as usize] = j_another;
            frontier[j_another as usize] = i_another;
        }
    }
    false
}

/// Forget closed or isolated endpoint `i` in `frontier`.
/// Returns `true` iff this operation results in inconsistency.
fn forget(frontier: &mut Frontier, i: i32) -> bool {
    frontier[i as usize] != CLOSED_END && frontier[i as usize] != i
}

/// Connect endpoint `i` in `frontier` to a number cell with value `num` directly.
/// Returns `true` iff this operation results in inconsistency.
fn connect_to_number(frontier: &mut Frontier, i: i32, num: i32) -> bool {
    let i = i as usize;
    let another = frontier[i];
    if another == CLOSED_END {
        return true;
    }
    frontier[i] = CLOSED_END;

    if another < 0 {
        num != another
    } else {
        frontier[another as usize] = num;
        false
    }
}

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

    fn run_problem_test(input: &[&str]) {
        let height = (input.len() / 2 + 1) as i32;
        let width = (input[0].len() / 2 + 1) as i32;

        let mut problem = Grid::new(height, width, NO_CLUE);
        for y in 0..height {
            let mut row_iter = input[(y * 2) as usize].chars();

            for x in 0..width {
                if x > 0 { row_iter.next(); }
                let c = row_iter.next().unwrap();
                if '1' <= c && c <= '9' {
                    problem[(Y(y), X(x))] = Clue(((c as u8) - ('0' as u8)) as i32);
                }
            }
        }

        let ans = solve(&problem);
        assert_eq!(ans.len(), 1);

        let ans = &ans[0];

        for y in 0..(2 * height - 1) {
            let mut row_iter = input[y as usize].chars();

            for x in 0..(2 * width - 1) {
                let c = row_iter.next().unwrap();
                if y % 2 == 1 && x % 2 == 0 {
                    assert_eq!(ans.down((Y(y / 2), X(x / 2))), c == '|');
                } else if y % 2 == 0 && x % 2 == 1 {
                    assert_eq!(ans.right((Y(y / 2), X(x / 2))), c == '-', "{} {}", y, x);
                }
            }
        }
    }

    #[test]
    fn test_solver() {
        run_problem_test(&[
            "+-2 4-+-+",
            "|       |",
            "+ 1-+-1 4",
            "|        ",
            "+ 3 2-+-+",
            "| |     |",
            "+ +-+-3 +",
            "|       |",
            "+-+-+-+-+",
        ]);
    }
}
<|endoftext|>