<commit_before>#![allow(clippy::non_ascii_literal)]

#[macro_use]
mod macros;

use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
use std::iter::FromIterator;
use syn::Stmt;

#[test]
fn test_raw_operator() {
    let stmt = syn::parse_str::<Stmt>("let _ = &raw const x;").unwrap();

    snapshot!(stmt, @r###"
    Local(Local {
        pat: Pat::Wild,
        init: Some(Verbatim(`& raw const x`)),
    })
    "###);
}

#[test]
fn test_raw_variable() {
    let stmt = syn::parse_str::<Stmt>("let _ = &raw;").unwrap();

    snapshot!(stmt, @r###"
    Local(Local {
        pat: Pat::Wild,
        init: Some(Expr::Reference {
            expr: Expr::Path {
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "raw",
                            arguments: None,
                        },
                    ],
                },
            },
        }),
    })
    "###);
}

#[test]
fn test_raw_invalid() {
    assert!(syn::parse_str::<Stmt>("let _ = &raw x;").is_err());
}

#[test]
fn test_none_group() {
    // <Ø async fn f() {} Ø>
    let tokens = TokenStream::from_iter(vec![TokenTree::Group(Group::new(
        Delimiter::None,
        TokenStream::from_iter(vec![
            TokenTree::Ident(Ident::new("async", Span::call_site())),
            TokenTree::Ident(Ident::new("fn", Span::call_site())),
            TokenTree::Ident(Ident::new("f", Span::call_site())),
            TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
            TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
        ]),
    ))]);

    snapshot!(tokens as Stmt, @r###"
    Item(Item::Fn {
        vis: Inherited,
        sig: Signature {
            asyncness: Some,
            ident: "f",
            generics: Generics,
            output: Default,
        },
        block: Block,
    })
    "###);
}
<commit_msg>Add test of let dot dot<commit_after>#![allow(clippy::non_ascii_literal)]

#[macro_use]
mod macros;

use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::Stmt;

#[test]
fn test_raw_operator() {
    let stmt = syn::parse_str::<Stmt>("let _ = &raw const x;").unwrap();

    snapshot!(stmt, @r###"
    Local(Local {
        pat: Pat::Wild,
        init: Some(Verbatim(`& raw const x`)),
    })
    "###);
}

#[test]
fn test_raw_variable() {
    let stmt = syn::parse_str::<Stmt>("let _ = &raw;").unwrap();

    snapshot!(stmt, @r###"
    Local(Local {
        pat: Pat::Wild,
        init: Some(Expr::Reference {
            expr: Expr::Path {
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "raw",
                            arguments: None,
                        },
                    ],
                },
            },
        }),
    })
    "###);
}

#[test]
fn test_raw_invalid() {
    assert!(syn::parse_str::<Stmt>("let _ = &raw x;").is_err());
}

#[test]
fn test_none_group() {
    // <Ø async fn f() {} Ø>
    let tokens = TokenStream::from_iter(vec![TokenTree::Group(Group::new(
        Delimiter::None,
        TokenStream::from_iter(vec![
            TokenTree::Ident(Ident::new("async", Span::call_site())),
            TokenTree::Ident(Ident::new("fn", Span::call_site())),
            TokenTree::Ident(Ident::new("f", Span::call_site())),
            TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
            TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
        ]),
    ))]);

    snapshot!(tokens as Stmt, @r###"
    Item(Item::Fn {
        vis: Inherited,
        sig: Signature {
            asyncness: Some,
            ident: "f",
            generics: Generics,
            output: Default,
        },
        block: Block,
    })
    "###);
}

#[test]
fn test_let_dot_dot() {
    let tokens = quote! {
        let .. = 10;
    };

    snapshot!(tokens as Stmt, @r###"
    Local(Local {
        pat: Pat::Rest,
        init: Some(Expr::Lit {
            lit: 10,
        }),
    })
    "###);
}
<|endoftext|>


<commit_before>#![allow(dead_code,
         non_camel_case_types,
         non_upper_case_globals,
         non_snake_case)]

use core::mem;
use core::ops::{Deref, DerefMut};
use core::convert::TryFrom;

use mouros_rust_bindings::CVoid;
use mouros_rust_bindings::mailbox::MailboxRaw;

#[repr(C)]
pub struct message {
    pub msg_type: u32,
    transaction_id: u32,
    pub data: *mut CVoid,
}

#[repr(C)]
pub struct message_handler {
    pub message_name: *const u8,
    pub parsing_func:
        Option<unsafe extern "C" fn(msg_ptr: *mut message, save_ptr: *mut u8) -> bool>,
    pub serialization_func: Option<
        unsafe extern "C" fn(msg_ptr: *const message,
                             output_str: *mut u8,
                             output_str_max_len: u32)
                             -> isize,
    >,
}

#[repr(C)]
pub struct subsystem_message_conf {
    pub subsystem_name: *const u8,
    pub message_handlers: *const message_handler,
    pub num_message_types: u32,
    pub incoming_msg_queue: *mut MailboxRaw,
    pub outgoing_msg_queue: *mut MailboxRaw,
    pub outgoing_err_queue: *mut MailboxRaw,
    pub alloc_message: Option<unsafe extern "C" fn(msg_type_id: u32) -> *mut message>,
    pub free_message: Option<unsafe extern "C" fn(msg: *mut message)>,
}

extern "C" {
    pub fn dispatcher_register_subsystem(conf: *mut subsystem_message_conf) -> bool;
}

pub struct MessageWrapper<T: Wrappable> {
    raw_msg_ptr: *mut message,
    msg: T,
}

pub trait MemManagement {
    fn alloc(msg_type: u32) -> *mut message;
    fn free(msg_ptr: *mut message);
}

pub trait Wrappable: MemManagement + TryFrom<*mut message, Error = ()> {}
impl<T> Wrappable for T
where
    T: MemManagement + TryFrom<*mut message, Error = ()>,
{
}

impl<T> Drop for MessageWrapper<T>
where
    T: Wrappable,
{
    fn drop(&mut self) {
        T::free(self.raw_msg_ptr);
    }
}

impl<T> Deref for MessageWrapper<T>
where
    T: Wrappable,
{
    type Target = T;

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

impl<T> DerefMut for MessageWrapper<T>
where
    T: Wrappable,
{
    fn deref_mut(&mut self) -> &mut T {
        &mut self.msg
    }
}

impl<T> Into<*mut message> for MessageWrapper<T>
where
    T: Wrappable,
{
    fn into(self) -> *mut message {
        let raw_msg_ptr = self.raw_msg_ptr;

        // It's the caller's duty ot deallocate the message now.
        mem::forget(self);

        raw_msg_ptr
    }
}

impl<T> TryFrom<*mut message> for MessageWrapper<T>
where
    T: Wrappable,
{
    type Error = ();

    fn try_from(raw_msg_ptr: *mut message) -> Result<Self, Self::Error> {
        unsafe {
            if raw_msg_ptr.is_null() || (*raw_msg_ptr).data.is_null() {
                return Err(());
            }
        };

        Ok(MessageWrapper {
            msg: T::try_from(raw_msg_ptr)?,
            raw_msg_ptr: raw_msg_ptr,
        })
    }
}

impl<T> MessageWrapper<T>
where
    T: Wrappable,
{
    pub fn new(trans_id: u32, msg_type: u32) -> Result<MessageWrapper<T>, ()> {

        if let Ok(msg_wrapper) = MessageWrapper::try_from(T::alloc(msg_type)) {
            unsafe {
                (*msg_wrapper.raw_msg_ptr).transaction_id = trans_id;
            }

            Ok(msg_wrapper)
        } else {
            Err(())
        }
    }

    pub fn get_transaction_id(&self) -> u32 {
        unsafe { (*self.raw_msg_ptr).transaction_id }
    }
}

pub struct SyncMemory<T>(T);
unsafe impl<T> Sync for SyncMemory<T> {}

impl<T> SyncMemory<T> {
    pub fn new(item: T) -> SyncMemory<T> {
        SyncMemory(item)
    }
}

impl<T> AsRef<T> for SyncMemory<T> {
    fn as_ref(&self) -> &T {
        &self.0
    }
}

impl<T> AsMut<T> for SyncMemory<T> {
    fn as_mut(&mut self) -> &mut T {
        &mut self.0
    }
}

#[macro_export]
macro_rules! unwrap_or_ret_false {
    ($wrapped:expr) => {
        if let Ok(unwrapped) = $wrapped {
            unwrapped
        } else {
            return false;
        }
    }
}
<commit_msg>Added MessageWrapper derivation macro<commit_after>#![allow(dead_code,
         non_camel_case_types,
         non_upper_case_globals,
         non_snake_case)]

use core::mem;
use core::ops::{Deref, DerefMut};
pub use core::convert::TryFrom;

use mouros_rust_bindings::CVoid;
use mouros_rust_bindings::mailbox::MailboxRaw;

#[repr(C)]
pub struct message {
    pub msg_type: u32,
    transaction_id: u32,
    pub data: *mut CVoid,
}

#[repr(C)]
pub struct message_handler {
    pub message_name: *const u8,
    pub parsing_func:
        Option<unsafe extern "C" fn(msg_ptr: *mut message, save_ptr: *mut u8) -> bool>,
    pub serialization_func: Option<
        unsafe extern "C" fn(msg_ptr: *const message,
                             output_str: *mut u8,
                             output_str_max_len: u32)
                             -> isize,
    >,
}

#[repr(C)]
pub struct subsystem_message_conf {
    pub subsystem_name: *const u8,
    pub message_handlers: *const message_handler,
    pub num_message_types: u32,
    pub incoming_msg_queue: *mut MailboxRaw,
    pub outgoing_msg_queue: *mut MailboxRaw,
    pub outgoing_err_queue: *mut MailboxRaw,
    pub alloc_message: Option<unsafe extern "C" fn(msg_type_id: u32) -> *mut message>,
    pub free_message: Option<unsafe extern "C" fn(msg: *mut message)>,
}

extern "C" {
    pub fn dispatcher_register_subsystem(conf: *mut subsystem_message_conf) -> bool;
}

pub struct MessageWrapper<T: Wrappable> {
    raw_msg_ptr: *mut message,
    msg: T,
}

pub trait MemManagement {
    fn alloc(msg_type: u32) -> *mut message;
    fn free(msg_ptr: *mut message);
}

pub trait Wrappable: MemManagement + TryFrom<*mut message, Error = ()> {}
impl<T> Wrappable for T
where
    T: MemManagement + TryFrom<*mut message, Error = ()>,
{
}

impl<T> Drop for MessageWrapper<T>
where
    T: Wrappable,
{
    fn drop(&mut self) {
        T::free(self.raw_msg_ptr);
    }
}

impl<T> Deref for MessageWrapper<T>
where
    T: Wrappable,
{
    type Target = T;

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

impl<T> DerefMut for MessageWrapper<T>
where
    T: Wrappable,
{
    fn deref_mut(&mut self) -> &mut T {
        &mut self.msg
    }
}

impl<T> Into<*mut message> for MessageWrapper<T>
where
    T: Wrappable,
{
    fn into(self) -> *mut message {
        let raw_msg_ptr = self.raw_msg_ptr;

        // It's the caller's duty ot deallocate the message now.
        mem::forget(self);

        raw_msg_ptr
    }
}

impl<T> TryFrom<*mut message> for MessageWrapper<T>
where
    T: Wrappable,
{
    type Error = ();

    fn try_from(raw_msg_ptr: *mut message) -> Result<Self, Self::Error> {
        unsafe {
            if raw_msg_ptr.is_null() || (*raw_msg_ptr).data.is_null() {
                return Err(());
            }
        };

        Ok(MessageWrapper {
            msg: T::try_from(raw_msg_ptr)?,
            raw_msg_ptr: raw_msg_ptr,
        })
    }
}

impl<T> MessageWrapper<T>
where
    T: Wrappable,
{
    pub fn new(trans_id: u32, msg_type: u32) -> Result<MessageWrapper<T>, ()> {

        if let Ok(msg_wrapper) = MessageWrapper::try_from(T::alloc(msg_type)) {
            unsafe {
                (*msg_wrapper.raw_msg_ptr).transaction_id = trans_id;
            }

            Ok(msg_wrapper)
        } else {
            Err(())
        }
    }

    pub fn get_transaction_id(&self) -> u32 {
        unsafe { (*self.raw_msg_ptr).transaction_id }
    }
}

#[macro_export]
macro_rules! derive_message_wrapper {
    ($type_name:tt<$($lifetime:tt),+>, $msg_id:ident => ( $($parsing_expr:tt)+ ), $alloc_func:expr, $free_func:expr) => (
        derive_message_wrapper!(
            $type_name<$($lifetime),+>,
            [$msg_id => ( $($parsing_expr)+ )],
            $alloc_func, $free_func);
    );

    ($type_name:tt<$($lifetime:tt),+>, [$( $msg_id:ident => ( $($parsing_expr:tt)+ ) ),+], $alloc_func:expr, $free_func:expr) => (
        impl<$($lifetime),+> $crate::bindings::message_dispatcher::TryFrom<*mut $crate::bindings::message_dispatcher::message> for $type_name<$($lifetime),+> {
            derive_message_wrapper!(@try_from_impl
                $type_name<$($lifetime),+>,
                [$( $msg_id => ( $($parsing_expr)+ ) ),+]);
        }

        impl<$($lifetime),+> $crate::bindings::message_dispatcher::MemManagement for $type_name<$($lifetime),+> {
            derive_message_wrapper!(@mem_mgnt_impl $alloc_func, $free_func);
        }
    );

    ($type_name:ty, $msg_id:ident => ( $($parsing_expr:tt)+ ), $alloc_func:expr, $free_func:expr) => (
        derive_message_wrapper!(
            $type_name,
            [$msg_id => ( $($parsing_expr)+ )], $alloc_func, $free_func);
    );

    ($type_name:ty, [$( $msg_id:ident => ( $($parsing_expr:tt)+ ) ),+], $alloc_func:expr, $free_func:expr) => (
        impl $crate::bindings::message_dispatcher::TryFrom<*mut $crate::bindings::message_dispatcher::message> for $type_name {
            derive_message_wrapper!(@try_from_impl
                $type_name,
                [$($msg_id => ( $($parsing_expr)+ ) ),+]);
        }

        impl $crate::bindings::message_dispatcher::MemManagement for $type_name {
            derive_message_wrapper!(@mem_mgnt_impl $alloc_func, $free_func);
        }
    );

    (@try_from_impl $type_name:ty, [$($msg_id:ident => ( $($parsing_expr:tt)+ ) ),+]) => (
        type Error = ();

        fn try_from(raw_ptr: *mut $crate::bindings::message_dispatcher::message) -> Result<$type_name, Self::Error> {
            unsafe {
                if raw_ptr.is_null() {
                    return Err(());
                }

                #[allow(unused_variables)]
                let data_ptr = (*raw_ptr).data;

                match (*raw_ptr).msg_type {
                    $($msg_id => {derive_message_wrapper!(@match_pattern data_ptr, $($parsing_expr)+ )},)+
                    _ => Err(())
                }
            }
        }
    );

    (@match_pattern $_payload_ptr:expr, $type_head:tt$(::$type_tail:tt)* ) => {
        Ok($type_head$(::$type_tail)*)
    };

    (@match_pattern $payload_ptr:expr, $($parsing_expr:tt)+ ) => {
        {
            if $payload_ptr.is_null() {
                return Err(());
            }

            derive_message_wrapper!(@as_expr $($parsing_expr)+)($payload_ptr)
        }
    };

    (@mem_mgnt_impl $alloc_func:expr, $free_func:expr) => {
        fn alloc(msg_type: u32) -> *mut $crate::bindings::message_dispatcher::message {
            #[allow(unused_unsafe)]
            unsafe { $alloc_func(msg_type) }
        }

        fn free(msg_ptr: *mut $crate::bindings::message_dispatcher::message) {
            #[allow(unused_unsafe)]
            unsafe { $free_func(msg_ptr); }
        }
    };

    (@as_expr $e:expr) => {$e};
}

pub struct SyncMemory<T>(T);
unsafe impl<T> Sync for SyncMemory<T> {}

impl<T> SyncMemory<T> {
    pub fn new(item: T) -> SyncMemory<T> {
        SyncMemory(item)
    }
}

impl<T> AsRef<T> for SyncMemory<T> {
    fn as_ref(&self) -> &T {
        &self.0
    }
}

impl<T> AsMut<T> for SyncMemory<T> {
    fn as_mut(&mut self) -> &mut T {
        &mut self.0
    }
}

#[macro_export]
macro_rules! unwrap_or_ret_false {
    ($wrapped:expr) => {
        if let Ok(unwrapped) = $wrapped {
            unwrapped
        } else {
            return false;
        }
    }
}
<|endoftext|>


<commit_before>use std;
use std::f32::consts::PI;

use arrayvec::ArrayVec;
use num::complex::Complex32;
use collect_slice::CollectSlice;

use consts::SAMPLES;
use descramble::VoiceDecisions;
use enhance::EnhancedSpectrals;
use noise::Noise;
use params::BaseParams;
use window;

// Result of equation 121
const SCALING_NUMER: f32 = 146.6432708443356;
const SCALING_DENOM: f32 = 3.33198263;
const SCALING_COEF: f32 = SCALING_NUMER / SCALING_DENOM;

pub struct UnvoicedDFT(ArrayVec<[Complex32; 256]>);

impl UnvoicedDFT {
    pub fn new(lower: isize, upper: isize, noise: &Noise, window: &window::Window)
        -> UnvoicedDFT
    {
        UnvoicedDFT((lower..upper).map(|m| {
            let mut nclone = noise.clone();

            (-104..105).map(|n| {
                nclone.next() * window.get(n) *
                    Complex32::new(0.0, -2.0 / 256.0 * PI * m as f32 * n as f32).exp()
            }).fold(Complex32::new(0.0, 0.0), |s, x| s + x)
        }).collect())
    }
}

impl std::ops::Deref for UnvoicedDFT {
    type Target = ArrayVec<[Complex32; 256]>;
    fn deref(&self) -> &Self::Target { &self.0 }
}

fn edges(l: usize, params: &BaseParams) -> (isize, isize) {
    let edge = |inner: f32| {
        256.0 / (2.0 * PI) * inner * params.fundamental
    };

    (
        edge(l as f32 - 0.5).ceil() as isize,
        edge(l as f32 + 0.5).ceil() as isize,
    )
}

pub struct UnvoicedParts([Complex32; 256]);

impl UnvoicedParts {
    pub fn new(params: &BaseParams, voice: &VoiceDecisions, enhanced: &EnhancedSpectrals)
        -> UnvoicedParts
    {
        let mut parts = [Complex32::new(0.0, 0.0); 256];

        let noise = Noise::new();
        let window = window::synthesis_trunc();

        for l in 1..params.harmonics as usize+1 {
            if voice.is_voiced(l) {
                continue;
            }

            let (lower, upper) = edges(l, params);
            let scale = SCALING_COEF * enhanced.get(l);

            let pos = UnvoicedDFT::new(lower, upper, &noise, &window);
            let neg = UnvoicedDFT::new(-upper+1, -lower+1, &noise, &window);

            pos.iter()
               .map(|&dft| scale * dft)
               .collect_slice(&mut parts[128 + lower as usize..]);

            neg.iter()
               .map(|&dft| scale * dft)
               .collect_slice(&mut parts[129 - upper as usize..]);
        }

        UnvoicedParts(parts)
    }

    // -128 <= m < 128
    fn get(&self, m: isize) -> Complex32 { self.0[(m + 128) as usize] }

    pub fn idft(&self, n: isize) -> f32 {
        if n < -128 || n > 127 {
            return 0.0;
        }

        (-128..128).map(|m| {
            self.get(m) *
                Complex32::new(0.0, 2.0 / 256.0 * PI * m as f32 * n as f32).exp()
        }).fold(Complex32::new(0.0, 0.0), |s, x| s + x).re / 256.0
    }
}

impl Default for UnvoicedParts {
    fn default() -> UnvoicedParts {
        UnvoicedParts([Complex32::new(0.0, 0.0); 256])
    }
}

pub struct Unvoiced<'a, 'b> {
    cur: &'a UnvoicedParts,
    prev: &'b UnvoicedParts,
    window: window::Window,
}

impl<'a, 'b> Unvoiced<'a, 'b> {
    pub fn new(cur: &'a UnvoicedParts, prev: &'b UnvoicedParts) -> Unvoiced<'a, 'b> {
        Unvoiced {
            cur: cur,
            prev: prev,
            window: window::synthesis_full(),
        }
    }

    pub fn get(&self, n: usize) -> f32 {
        let n = n as isize;

        let numer = self.window.get(n) * self.prev.idft(n) +
            self.window.get(n - SAMPLES as isize) * self.cur.idft(n - SAMPLES as isize);
        let denom = self.window.get(n).powi(2) +
            self.window.get(n - SAMPLES as isize).powi(2);

        numer / denom
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::edges;
    use descramble::Bootstrap;
    use params::BaseParams;

    #[test]
    fn test_edges() {
        let chunks = [
            0b001000010010,
            0b110011001100,
            0b111000111000,
            0b111111111111,
            0b10100110101,
            0b00101111010,
            0b01110111011,
            0b00001000,
        ];

        let b = Bootstrap::new(&chunks);
        let p = BaseParams::new(b.unwrap_period());

        assert!((p.fundamental - 0.17575344).abs() < 0.000001);

        let (lower, upper) = edges(1, &p);
        assert_eq!(lower, 4);
        assert_eq!(upper, 11);

        let (lower, upper) = edges(2, &p);
        assert_eq!(lower, 11);
        assert_eq!(upper, 18);

        let (lower, upper) = edges(5, &p);
        assert_eq!(lower, 33);
        assert_eq!(upper, 40);

        let (lower, upper) = edges(8, &p);
        assert_eq!(lower, 54);
        assert_eq!(upper, 61);

        let (lower, upper) = edges(16, &p);
        assert_eq!(lower, 111);
        assert_eq!(upper, 119);
    }
}
<commit_msg>Coefficient of 5 seems to sound better<commit_after>use std;
use std::f32::consts::PI;

use arrayvec::ArrayVec;
use num::complex::Complex32;
use collect_slice::CollectSlice;

use consts::SAMPLES;
use descramble::VoiceDecisions;
use enhance::EnhancedSpectrals;
use noise::Noise;
use params::BaseParams;
use window;

// Result of equation 121
const SCALING_COEF: f32 = 5.0;

pub struct UnvoicedDFT(ArrayVec<[Complex32; 256]>);

impl UnvoicedDFT {
    pub fn new(lower: isize, upper: isize, noise: &Noise, window: &window::Window)
        -> UnvoicedDFT
    {
        UnvoicedDFT((lower..upper).map(|m| {
            let mut nclone = noise.clone();

            (-104..105).map(|n| {
                nclone.next() * window.get(n) *
                    Complex32::new(0.0, -2.0 / 256.0 * PI * m as f32 * n as f32).exp()
            }).fold(Complex32::new(0.0, 0.0), |s, x| s + x)
        }).collect())
    }
}

impl std::ops::Deref for UnvoicedDFT {
    type Target = ArrayVec<[Complex32; 256]>;
    fn deref(&self) -> &Self::Target { &self.0 }
}

fn edges(l: usize, params: &BaseParams) -> (isize, isize) {
    let edge = |inner: f32| {
        256.0 / (2.0 * PI) * inner * params.fundamental
    };

    (
        edge(l as f32 - 0.5).ceil() as isize,
        edge(l as f32 + 0.5).ceil() as isize,
    )
}

pub struct UnvoicedParts([Complex32; 256]);

impl UnvoicedParts {
    pub fn new(params: &BaseParams, voice: &VoiceDecisions, enhanced: &EnhancedSpectrals)
        -> UnvoicedParts
    {
        let mut parts = [Complex32::new(0.0, 0.0); 256];

        let noise = Noise::new();
        let window = window::synthesis_trunc();

        for l in 1..params.harmonics as usize+1 {
            if voice.is_voiced(l) {
                continue;
            }

            let (lower, upper) = edges(l, params);
            let scale = SCALING_COEF * enhanced.get(l);

            let pos = UnvoicedDFT::new(lower, upper, &noise, &window);
            let neg = UnvoicedDFT::new(-upper+1, -lower+1, &noise, &window);

            pos.iter()
               .map(|&dft| scale * dft)
               .collect_slice(&mut parts[128 + lower as usize..]);

            neg.iter()
               .map(|&dft| scale * dft)
               .collect_slice(&mut parts[129 - upper as usize..]);
        }

        UnvoicedParts(parts)
    }

    // -128 <= m < 128
    fn get(&self, m: isize) -> Complex32 { self.0[(m + 128) as usize] }

    pub fn idft(&self, n: isize) -> f32 {
        if n < -128 || n > 127 {
            return 0.0;
        }

        (-128..128).map(|m| {
            self.get(m) *
                Complex32::new(0.0, 2.0 / 256.0 * PI * m as f32 * n as f32).exp()
        }).fold(Complex32::new(0.0, 0.0), |s, x| s + x).re / 256.0
    }
}

impl Default for UnvoicedParts {
    fn default() -> UnvoicedParts {
        UnvoicedParts([Complex32::new(0.0, 0.0); 256])
    }
}

pub struct Unvoiced<'a, 'b> {
    cur: &'a UnvoicedParts,
    prev: &'b UnvoicedParts,
    window: window::Window,
}

impl<'a, 'b> Unvoiced<'a, 'b> {
    pub fn new(cur: &'a UnvoicedParts, prev: &'b UnvoicedParts) -> Unvoiced<'a, 'b> {
        Unvoiced {
            cur: cur,
            prev: prev,
            window: window::synthesis_full(),
        }
    }

    pub fn get(&self, n: usize) -> f32 {
        let n = n as isize;

        let numer = self.window.get(n) * self.prev.idft(n) +
            self.window.get(n - SAMPLES as isize) * self.cur.idft(n - SAMPLES as isize);
        let denom = self.window.get(n).powi(2) +
            self.window.get(n - SAMPLES as isize).powi(2);

        numer / denom
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::edges;
    use descramble::Bootstrap;
    use params::BaseParams;

    #[test]
    fn test_edges() {
        let chunks = [
            0b001000010010,
            0b110011001100,
            0b111000111000,
            0b111111111111,
            0b10100110101,
            0b00101111010,
            0b01110111011,
            0b00001000,
        ];

        let b = Bootstrap::new(&chunks);
        let p = BaseParams::new(b.unwrap_period());

        assert!((p.fundamental - 0.17575344).abs() < 0.000001);

        let (lower, upper) = edges(1, &p);
        assert_eq!(lower, 4);
        assert_eq!(upper, 11);

        let (lower, upper) = edges(2, &p);
        assert_eq!(lower, 11);
        assert_eq!(upper, 18);

        let (lower, upper) = edges(5, &p);
        assert_eq!(lower, 33);
        assert_eq!(upper, 40);

        let (lower, upper) = edges(8, &p);
        assert_eq!(lower, 54);
        assert_eq!(upper, 61);

        let (lower, upper) = edges(16, &p);
        assert_eq!(lower, 111);
        assert_eq!(upper, 119);
    }
}
<|endoftext|>


<commit_before>use std::path::{Path, Component};
use std::error::Error;
use std::io::{self, Read};
use std::fs::{self, File};

/// Takes a path to a file and try to read the file into a String

pub fn file_to_string(path: &Path) -> Result<String, Box<Error>> {
    let mut file = match File::open(path) {
        Ok(f) => f,
        Err(e) => {
            debug!("[*]: Failed to open {:?}", path);
            return Err(Box::new(e));
        },
    };

    let mut content = String::new();

    if let Err(e) = file.read_to_string(&mut content) {
        debug!("[*]: Failed to read {:?}", path);
        return Err(Box::new(e));
    }

    Ok(content)
}

/// Takes a path and returns a path containing just enough `../` to point to the root of the given path.
///
/// This is mostly interesting for a relative path to point back to the directory from where the
/// path starts.
///
/// ```ignore
/// let mut path = Path::new("some/relative/path");
///
/// println!("{}", path_to_root(&path));
/// ```
///
/// **Outputs**
///
/// ```text
/// "../../"
/// ```
///
/// **note:** it's not very fool-proof, if you find a situation where it doesn't return the correct
/// path. Consider [submitting a new issue](https://github.com/azerupi/mdBook/issues) or a
/// [pull-request](https://github.com/azerupi/mdBook/pulls) to improve it.

pub fn path_to_root(path: &Path) -> String {
    debug!("[fn]: path_to_root");
    // Remove filename and add "../" for every directory

    path.to_path_buf()
        .parent()
        .expect("")
        .components()
        .fold(String::new(), |mut s, c| {
            match c {
                Component::Normal(_) => s.push_str("../"),
                _ => {
                    debug!("[*]: Other path component... {:?}", c);
                },
            }
            s
        })
}

/// This function creates a file and returns it. But before creating the file it checks every
/// directory in the path to see if it exists, and if it does not it will be created.

pub fn create_file(path: &Path) -> Result<File, Box<Error>> {
    debug!("[fn]: create_file");

    // Construct path
    if let Some(p) = path.parent() {
        debug!("Parent directory is: {:?}", p);

        try!(fs::create_dir_all(p));
    }

    debug!("[*]: Create file: {:?}", path);
    let f = match File::create(path) {
        Ok(f) => f,
        Err(e) => {
            debug!("File::create:    {}", e);
            return Err(Box::new(io::Error::new(io::ErrorKind::Other, format!("{}", e))));
        },
    };

    Ok(f)
}

/// Removes all the content of a directory but not the directory itself

pub fn remove_dir_content(dir: &Path) -> Result<(), Box<Error>> {
    for item in try!(fs::read_dir(dir)) {
        if let Ok(item) = item {
            let item = item.path();
            if item.is_dir() {
                try!(fs::remove_dir_all(item));
            } else {
                try!(fs::remove_file(item));
            }
        }
    }
    Ok(())
}

///
///
/// Copies all files of a directory to another one except the files with the extensions given in the
/// `ext_blacklist` array

pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blacklist: &[&str]) -> Result<(), Box<Error>> {
    debug!("[fn] copy_files_except_ext");
    // Check that from and to are different
    if from == to {
        return Ok(());
    }
    debug!("[*] Loop");
    for entry in try!(fs::read_dir(from)) {
        let entry = try!(entry);
        debug!("[*] {:?}", entry.path());
        let metadata = try!(entry.metadata());

        // If the entry is a dir and the recursive option is enabled, call itself
        if metadata.is_dir() && recursive {
            if entry.path() == to.to_path_buf() {
                continue;
            }
            debug!("[*] is dir");

            // check if output dir already exists
            if !to.join(entry.file_name()).exists() {
                try!(fs::create_dir(&to.join(entry.file_name())));
            }

            try!(copy_files_except_ext(&from.join(entry.file_name()),
                                       &to.join(entry.file_name()),
                                       true,
                                       ext_blacklist));
        } else if metadata.is_file() {

            // Check if it is in the blacklist
            if let Some(ext) = entry.path().extension() {
                if ext_blacklist.contains(&ext.to_str().unwrap()) {
                    continue;
                }
            }
            debug!("[*] creating path for file: {:?}",
                   &to.join(entry.path().file_name().expect("a file should have a file name...")));

            info!("[*] Copying file: {:?}\n    to {:?}",
                  entry.path(),
                  &to.join(entry.path().file_name().expect("a file should have a file name...")));
            try!(fs::copy(entry.path(),
                          &to.join(entry.path().file_name().expect("a file should have a file name..."))));
        }
    }
    Ok(())
}

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------

// tests

#[cfg(test)]
mod tests {
    extern crate tempdir;

    use super::copy_files_except_ext;
    use std::fs;

    #[test]
    fn copy_files_except_ext_test() {
        let tmp = match tempdir::TempDir::new("") {
            Ok(t) => t,
            Err(_) => panic!("Could not create a temp dir"),
        };

        // Create a couple of files
        if let Err(_) = fs::File::create(&tmp.path().join("file.txt")) {
            panic!("Could not create file.txt")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("file.md")) {
            panic!("Could not create file.md")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("file.png")) {
            panic!("Could not create file.png")
        }
        if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir")) {
            panic!("Could not create sub_dir")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("sub_dir/file.png")) {
            panic!("Could not create sub_dir/file.png")
        }
        if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir_exists")) {
            panic!("Could not create sub_dir_exists")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) {
            panic!("Could not create sub_dir_exists/file.txt")
        }

        // Create output dir
        if let Err(_) = fs::create_dir(&tmp.path().join("output")) {
            panic!("Could not create output")
        }
        if let Err(_) = fs::create_dir(&tmp.path().join("output/sub_dir_exists")) {
            panic!("Could not create output/sub_dir_exists")
        }

        match copy_files_except_ext(&tmp.path(), &tmp.path().join("output"), true, &["md"]) {
            Err(e) => panic!("Error while executing the function:\n{:?}", e),
            Ok(_) => {},
        }

        // Check if the correct files where created
        if !(&tmp.path().join("output/file.txt")).exists() {
            panic!("output/file.txt should exist")
        }
        if (&tmp.path().join("output/file.md")).exists() {
            panic!("output/file.md should not exist")
        }
        if !(&tmp.path().join("output/file.png")).exists() {
            panic!("output/file.png should exist")
        }
        if !(&tmp.path().join("output/sub_dir/file.png")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }
        if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }

    }
}
<commit_msg>Simplify error handling in utils::fs<commit_after>use std::path::{Path, Component};
use std::error::Error;
use std::io::{self, Read};
use std::fs::{self, File};

/// Takes a path to a file and try to read the file into a String

pub fn file_to_string(path: &Path) -> Result<String, Box<Error>> {
    let mut file = match File::open(path) {
        Ok(f) => f,
        Err(e) => {
            debug!("[*]: Failed to open {:?}", path);
            return Err(Box::new(e));
        },
    };

    let mut content = String::new();

    if let Err(e) = file.read_to_string(&mut content) {
        debug!("[*]: Failed to read {:?}", path);
        return Err(Box::new(e));
    }

    Ok(content)
}

/// Takes a path and returns a path containing just enough `../` to point to the root of the given path.
///
/// This is mostly interesting for a relative path to point back to the directory from where the
/// path starts.
///
/// ```ignore
/// let mut path = Path::new("some/relative/path");
///
/// println!("{}", path_to_root(&path));
/// ```
///
/// **Outputs**
///
/// ```text
/// "../../"
/// ```
///
/// **note:** it's not very fool-proof, if you find a situation where it doesn't return the correct
/// path. Consider [submitting a new issue](https://github.com/azerupi/mdBook/issues) or a
/// [pull-request](https://github.com/azerupi/mdBook/pulls) to improve it.

pub fn path_to_root(path: &Path) -> String {
    debug!("[fn]: path_to_root");
    // Remove filename and add "../" for every directory

    path.to_path_buf()
        .parent()
        .expect("")
        .components()
        .fold(String::new(), |mut s, c| {
            match c {
                Component::Normal(_) => s.push_str("../"),
                _ => {
                    debug!("[*]: Other path component... {:?}", c);
                },
            }
            s
        })
}

/// This function creates a file and returns it. But before creating the file it checks every
/// directory in the path to see if it exists, and if it does not it will be created.

pub fn create_file(path: &Path) -> io::Result<File> {
    debug!("[fn]: create_file");

    // Construct path
    if let Some(p) = path.parent() {
        debug!("Parent directory is: {:?}", p);

        try!(fs::create_dir_all(p));
    }

    debug!("[*]: Create file: {:?}", path);
    File::create(path)
}

/// Removes all the content of a directory but not the directory itself

pub fn remove_dir_content(dir: &Path) -> Result<(), Box<Error>> {
    for item in try!(fs::read_dir(dir)) {
        if let Ok(item) = item {
            let item = item.path();
            if item.is_dir() {
                try!(fs::remove_dir_all(item));
            } else {
                try!(fs::remove_file(item));
            }
        }
    }
    Ok(())
}

///
///
/// Copies all files of a directory to another one except the files with the extensions given in the
/// `ext_blacklist` array

pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blacklist: &[&str]) -> Result<(), Box<Error>> {
    debug!("[fn] copy_files_except_ext");
    // Check that from and to are different
    if from == to {
        return Ok(());
    }
    debug!("[*] Loop");
    for entry in try!(fs::read_dir(from)) {
        let entry = try!(entry);
        debug!("[*] {:?}", entry.path());
        let metadata = try!(entry.metadata());

        // If the entry is a dir and the recursive option is enabled, call itself
        if metadata.is_dir() && recursive {
            if entry.path() == to.to_path_buf() {
                continue;
            }
            debug!("[*] is dir");

            // check if output dir already exists
            if !to.join(entry.file_name()).exists() {
                try!(fs::create_dir(&to.join(entry.file_name())));
            }

            try!(copy_files_except_ext(&from.join(entry.file_name()),
                                       &to.join(entry.file_name()),
                                       true,
                                       ext_blacklist));
        } else if metadata.is_file() {

            // Check if it is in the blacklist
            if let Some(ext) = entry.path().extension() {
                if ext_blacklist.contains(&ext.to_str().unwrap()) {
                    continue;
                }
            }
            debug!("[*] creating path for file: {:?}",
                   &to.join(entry.path().file_name().expect("a file should have a file name...")));

            info!("[*] Copying file: {:?}\n    to {:?}",
                  entry.path(),
                  &to.join(entry.path().file_name().expect("a file should have a file name...")));
            try!(fs::copy(entry.path(),
                          &to.join(entry.path().file_name().expect("a file should have a file name..."))));
        }
    }
    Ok(())
}

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------

// tests

#[cfg(test)]
mod tests {
    extern crate tempdir;

    use super::copy_files_except_ext;
    use std::fs;

    #[test]
    fn copy_files_except_ext_test() {
        let tmp = match tempdir::TempDir::new("") {
            Ok(t) => t,
            Err(_) => panic!("Could not create a temp dir"),
        };

        // Create a couple of files
        if let Err(_) = fs::File::create(&tmp.path().join("file.txt")) {
            panic!("Could not create file.txt")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("file.md")) {
            panic!("Could not create file.md")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("file.png")) {
            panic!("Could not create file.png")
        }
        if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir")) {
            panic!("Could not create sub_dir")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("sub_dir/file.png")) {
            panic!("Could not create sub_dir/file.png")
        }
        if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir_exists")) {
            panic!("Could not create sub_dir_exists")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) {
            panic!("Could not create sub_dir_exists/file.txt")
        }

        // Create output dir
        if let Err(_) = fs::create_dir(&tmp.path().join("output")) {
            panic!("Could not create output")
        }
        if let Err(_) = fs::create_dir(&tmp.path().join("output/sub_dir_exists")) {
            panic!("Could not create output/sub_dir_exists")
        }

        match copy_files_except_ext(&tmp.path(), &tmp.path().join("output"), true, &["md"]) {
            Err(e) => panic!("Error while executing the function:\n{:?}", e),
            Ok(_) => {},
        }

        // Check if the correct files where created
        if !(&tmp.path().join("output/file.txt")).exists() {
            panic!("output/file.txt should exist")
        }
        if (&tmp.path().join("output/file.md")).exists() {
            panic!("output/file.md should not exist")
        }
        if !(&tmp.path().join("output/file.png")).exists() {
            panic!("output/file.png should exist")
        }
        if !(&tmp.path().join("output/sub_dir/file.png")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }
        if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }

    }
}
<|endoftext|>


<commit_before>use base;
use regex::Regex;
use serialize;
use super::name::WadName;
use super::types::ThingType;
use toml;
use toml::{DecodeError, ApplicationError, ExpectedField, ExpectedType,
           ExpectedMapElement, ExpectedMapKey, NoEnumVariants, NilTooLong};

#[deriving(Decodable, Encodable)]
pub struct SkyMetadata {
    pub texture_name: WadName,
    pub level_pattern: String,
    pub tiled_band_size: f32,
}

#[deriving(Decodable, Encodable)]
pub struct AnimationMetadata {
    pub flats: Vec<Vec<WadName>>,
    pub walls: Vec<Vec<WadName>>,
}

#[deriving(Decodable, Encodable)]
pub struct ThingMetadata {
    pub thing_type: ThingType,
    pub sprite: WadName,
    pub sequence: String,
}

#[deriving(Decodable, Encodable)]
pub struct ThingDirectoryMetadata {
    pub decoration: Vec<ThingMetadata>
}

#[deriving(Decodable, Encodable)]
pub struct WadMetadata {
    pub sky: Vec<SkyMetadata>,
    pub animations: AnimationMetadata,
    pub things: ThingDirectoryMetadata,
}
impl WadMetadata {
    pub fn from_file(path: &Path) -> Result<WadMetadata, String> {
        base::read_utf8_file(path).and_then(
            |contents| WadMetadata::from_text(contents[]))
    }

    pub fn from_text(text: &str) -> Result<WadMetadata, String> {
        let mut parser = toml::Parser::new(text);
        match parser.parse() {
            Some(value) => serialize::Decodable::decode(
                    &mut toml::Decoder::new(toml::Value::Table(value)))
                .map_err(|e| show_decode_err(e)),
            None => Err(format!("Error parsing WadMetadata from TOML: {}",
                                parser.errors))
        }
    }

    pub fn sky_for(&self, name: &WadName) -> &SkyMetadata {
        for sky in self.sky.iter() {
            let regex = Regex::new(sky.level_pattern[]).unwrap();
            if regex.is_match(name.as_str()) {
                return sky;
            }
        }
        &self.sky[0]
    }
}

fn show_decode_err(err: DecodeError) -> String {
    format!("Error decoding WadMetadata: in field '{}': {}",
            err.field.unwrap_or("none".to_string()),
            match err.kind {
                ApplicationError(msg) => msg,
                ExpectedField(e) => format!("expected field '{}'", e),
                ExpectedType(e, f) => format!("expected type '{}', found '{}'",
                                              e, f),
                ExpectedMapKey(e) => format!("map key '{}' expected", e),
                ExpectedMapElement(e) => format!("map value '{}' expected", e),
                NoEnumVariants => format!("no enum variants"),
                NilTooLong => format!("non-empty string for nil type")
            })
}

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

    #[test]
    fn test_wad_metadata() {
        assert!("{}", WadMetadata::from_text(r#"
            [[sky]]
                level_range = [0, 10]
                texture_name = "SKY1"
                tiled_band_size = 0.15
            [[sky]]
                level_range = [11, 20]
                texture_name = "SKY2"
                tiled_band_size = 0.15
            [[sky]]
                level_range = [21, 35]
                texture_name = "SKY3"
                tiled_band_size = 0.15
        "#).is_ok());
    }
}

<commit_msg>Fix WadMetadata test<commit_after>use base;
use regex::Regex;
use serialize;
use super::name::WadName;
use super::types::ThingType;
use toml;
use toml::{DecodeError, ApplicationError, ExpectedField, ExpectedType,
           ExpectedMapElement, ExpectedMapKey, NoEnumVariants, NilTooLong};

#[deriving(Decodable, Encodable)]
pub struct SkyMetadata {
    pub texture_name: WadName,
    pub level_pattern: String,
    pub tiled_band_size: f32,
}

#[deriving(Decodable, Encodable)]
pub struct AnimationMetadata {
    pub flats: Vec<Vec<WadName>>,
    pub walls: Vec<Vec<WadName>>,
}

#[deriving(Decodable, Encodable)]
pub struct ThingMetadata {
    pub thing_type: ThingType,
    pub sprite: WadName,
    pub sequence: String,
}

#[deriving(Decodable, Encodable)]
pub struct ThingDirectoryMetadata {
    pub decoration: Vec<ThingMetadata>
}

#[deriving(Decodable, Encodable)]
pub struct WadMetadata {
    pub sky: Vec<SkyMetadata>,
    pub animations: AnimationMetadata,
    pub things: ThingDirectoryMetadata,
}
impl WadMetadata {
    pub fn from_file(path: &Path) -> Result<WadMetadata, String> {
        base::read_utf8_file(path).and_then(
            |contents| WadMetadata::from_text(contents[]))
    }

    pub fn from_text(text: &str) -> Result<WadMetadata, String> {
        let mut parser = toml::Parser::new(text);
        match parser.parse() {
            Some(value) => serialize::Decodable::decode(
                    &mut toml::Decoder::new(toml::Value::Table(value)))
                .map_err(|e| show_decode_err(e)),
            None => Err(format!("Error parsing WadMetadata from TOML: {}",
                                parser.errors))
        }
    }

    pub fn sky_for(&self, name: &WadName) -> &SkyMetadata {
        for sky in self.sky.iter() {
            let regex = Regex::new(sky.level_pattern[]).unwrap();
            if regex.is_match(name.as_str()) {
                return sky;
            }
        }
        &self.sky[0]
    }
}

fn show_decode_err(err: DecodeError) -> String {
    format!("Error decoding WadMetadata: in field '{}': {}",
            err.field.unwrap_or("none".to_string()),
            match err.kind {
                ApplicationError(msg) => msg,
                ExpectedField(e) => format!("expected field '{}'", e),
                ExpectedType(e, f) => format!("expected type '{}', found '{}'",
                                              e, f),
                ExpectedMapKey(e) => format!("map key '{}' expected", e),
                ExpectedMapElement(e) => format!("map value '{}' expected", e),
                NoEnumVariants => format!("no enum variants"),
                NilTooLong => format!("non-empty string for nil type")
            })
}

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

    #[test]
    fn test_wad_metadata() {
        WadMetadata::from_text(r#"
            [[sky]]
                level_pattern = "MAP(0[1-9]|10|11)"
                texture_name = "SKY1"
                tiled_band_size = 0.15
            [[sky]]
                level_pattern = "MAP(1[2-9]|20)"
                texture_name = "SKY2"
                tiled_band_size = 0.15
            [[sky]]
                level_pattern = "MAP(2[1-9]|32)"
                texture_name = "SKY3"
                tiled_band_size = 0.15
            [animations]
                flats = [
                    ["NUKAGE1", "NUKAGE2", "NUKAGE3"],
                    [],
                ]
                walls = [
                    [],
                    ["DBRAIN1", "DBRAIN2", "DBRAIN3",  "DBRAIN4"],
                ]
            [things]
                [[things.decoration]]
                    thing_type = 10
                    sprite = "PLAY"
                    sequence = "W"
                    obstacle = false
                    hanging = false

                [[things.decoration]]
                    thing_type = 12
                    sprite = "PLAY"
                    sequence = "W"
                    obstacle = false
                    hanging = false
        "#).unwrap();
    }
}

<|endoftext|>


<commit_before>use crate::syntax::improper::ImproperCtype;
use crate::syntax::report::Errors;
use crate::syntax::set::{OrderedSet as Set, UnorderedSet};
use crate::syntax::{
    toposort, Api, Enum, ExternFn, ExternType, Impl, Pair, RustName, Struct, Type, TypeAlias,
};
use proc_macro2::Ident;
use quote::ToTokens;
use std::collections::BTreeMap as Map;
use std::fmt::Display;

pub struct Types<'a> {
    pub all: Set<&'a Type>,
    pub structs: Map<&'a Ident, &'a Struct>,
    pub enums: Map<&'a Ident, &'a Enum>,
    pub cxx: Set<&'a Ident>,
    pub rust: Set<&'a Ident>,
    pub aliases: Map<&'a Ident, &'a TypeAlias>,
    pub untrusted: Map<&'a Ident, &'a ExternType>,
    pub required_trivial: Map<&'a Ident, Vec<TrivialReason<'a>>>,
    pub explicit_impls: Set<&'a Impl>,
    pub resolutions: Map<&'a RustName, &'a Pair>,
    pub struct_improper_ctypes: UnorderedSet<&'a Ident>,
    pub toposorted_structs: Vec<&'a Struct>,
}

impl<'a> Types<'a> {
    pub fn collect(cx: &mut Errors, apis: &'a [Api]) -> Self {
        let mut all = Set::new();
        let mut structs = Map::new();
        let mut enums = Map::new();
        let mut cxx = Set::new();
        let mut rust = Set::new();
        let mut aliases = Map::new();
        let mut untrusted = Map::new();
        let mut explicit_impls = Set::new();
        let mut resolutions = Map::new();
        let struct_improper_ctypes = UnorderedSet::new();
        let toposorted_structs = Vec::new();

        fn visit<'a>(all: &mut Set<&'a Type>, ty: &'a Type) {
            all.insert(ty);
            match ty {
                Type::Ident(_) | Type::Str(_) | Type::Void(_) => {}
                Type::RustBox(ty)
                | Type::UniquePtr(ty)
                | Type::SharedPtr(ty)
                | Type::CxxVector(ty)
                | Type::RustVec(ty) => visit(all, &ty.inner),
                Type::Ref(r) => visit(all, &r.inner),
                Type::Array(a) => visit(all, &a.inner),
                Type::SliceRef(s) => visit(all, &s.inner),
                Type::Fn(f) => {
                    if let Some(ret) = &f.ret {
                        visit(all, ret);
                    }
                    for arg in &f.args {
                        visit(all, &arg.ty);
                    }
                }
            }
        }

        let mut add_resolution = |pair: &'a Pair| {
            resolutions.insert(RustName::from_ref(&pair.rust), pair);
        };

        let mut type_names = UnorderedSet::new();
        let mut function_names = UnorderedSet::new();
        for api in apis {
            // The same identifier is permitted to be declared as both a shared
            // enum and extern C++ type, or shared struct and extern C++ type.
            // That indicates to not emit the C++ enum/struct definition because
            // it's defined by the included headers already.
            //
            // All other cases of duplicate identifiers are reported as an error.
            match api {
                Api::Include(_) => {}
                Api::Struct(strct) => {
                    let ident = &strct.name.rust;
                    if !type_names.insert(ident)
                        && (!cxx.contains(ident)
                            || structs.contains_key(ident)
                            || enums.contains_key(ident))
                    {
                        // If already declared as a struct or enum, or if
                        // colliding with something other than an extern C++
                        // type, then error.
                        duplicate_name(cx, strct, ident);
                    }
                    structs.insert(&strct.name.rust, strct);
                    for field in &strct.fields {
                        visit(&mut all, &field.ty);
                    }
                    add_resolution(&strct.name);
                }
                Api::Enum(enm) => {
                    all.insert(&enm.repr_type);
                    let ident = &enm.name.rust;
                    if !type_names.insert(ident)
                        && (!cxx.contains(ident)
                            || structs.contains_key(ident)
                            || enums.contains_key(ident))
                    {
                        // If already declared as a struct or enum, or if
                        // colliding with something other than an extern C++
                        // type, then error.
                        duplicate_name(cx, enm, ident);
                    }
                    enums.insert(ident, enm);
                    add_resolution(&enm.name);
                }
                Api::CxxType(ety) => {
                    let ident = &ety.name.rust;
                    if !type_names.insert(ident)
                        && (cxx.contains(ident)
                            || !structs.contains_key(ident) && !enums.contains_key(ident))
                    {
                        // If already declared as an extern C++ type, or if
                        // colliding with something which is neither struct nor
                        // enum, then error.
                        duplicate_name(cx, ety, ident);
                    }
                    cxx.insert(ident);
                    if !ety.trusted {
                        untrusted.insert(ident, ety);
                    }
                    add_resolution(&ety.name);
                }
                Api::RustType(ety) => {
                    let ident = &ety.name.rust;
                    if !type_names.insert(ident) {
                        duplicate_name(cx, ety, ident);
                    }
                    rust.insert(ident);
                    add_resolution(&ety.name);
                }
                Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                    // Note: duplication of the C++ name is fine because C++ has
                    // function overloading.
                    if !function_names.insert((&efn.receiver, &efn.name.rust)) {
                        duplicate_name(cx, efn, &efn.name.rust);
                    }
                    for arg in &efn.args {
                        visit(&mut all, &arg.ty);
                    }
                    if let Some(ret) = &efn.ret {
                        visit(&mut all, ret);
                    }
                }
                Api::TypeAlias(alias) => {
                    let ident = &alias.name.rust;
                    if !type_names.insert(ident) {
                        duplicate_name(cx, alias, ident);
                    }
                    cxx.insert(ident);
                    aliases.insert(ident, alias);
                    add_resolution(&alias.name);
                }
                Api::Impl(imp) => {
                    visit(&mut all, &imp.ty);
                    explicit_impls.insert(imp);
                }
            }
        }

        // All these APIs may contain types passed by value. We need to ensure
        // we check that this is permissible. We do this _after_ scanning all
        // the APIs above, in case some function or struct references a type
        // which is declared subsequently.
        let mut required_trivial: Map<_, Vec<_>> = Map::new();

        let mut insist_extern_types_are_trivial = |ident: &'a RustName, reason| {
            if cxx.contains(&ident.rust)
                && !structs.contains_key(&ident.rust)
                && !enums.contains_key(&ident.rust)
            {
                required_trivial
                    .entry(&ident.rust)
                    .or_default()
                    .push(reason);
            }
        };
        for api in apis {
            match api {
                Api::Struct(strct) => {
                    let reason = TrivialReason::StructField(strct);
                    for field in &strct.fields {
                        if let Type::Ident(ident) = &field.ty {
                            insist_extern_types_are_trivial(ident, reason);
                        }
                    }
                }
                Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                    let reason = TrivialReason::FunctionArgument(efn);
                    for arg in &efn.args {
                        if let Type::Ident(ident) = &arg.ty {
                            insist_extern_types_are_trivial(ident, reason);
                        }
                    }
                    if let Some(ret) = &efn.ret {
                        let reason = TrivialReason::FunctionReturn(efn);
                        if let Type::Ident(ident) = &ret {
                            insist_extern_types_are_trivial(ident, reason);
                        }
                    }
                }
                _ => {}
            }
        }
        for ty in &all {
            match ty {
                Type::RustBox(ty) => {
                    let reason = TrivialReason::BoxTarget;
                    if let Type::Ident(ident) = &ty.inner {
                        insist_extern_types_are_trivial(ident, reason);
                    }
                }
                Type::RustVec(ty) => {
                    let reason = TrivialReason::VecElement;
                    if let Type::Ident(ident) = &ty.inner {
                        insist_extern_types_are_trivial(ident, reason);
                    }
                }
                _ => {}
            }
        }
        for api in apis {
            match api {
                Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                    let reason = TrivialReason::UnpinnedMutArg(efn);
                    if let Some(receiver) = &efn.receiver {
                        if receiver.mutable && !receiver.pinned {
                            insist_extern_types_are_trivial(&receiver.ty, reason);
                        }
                    }
                    for arg in &efn.args {
                        if let Type::Ref(reff) = &arg.ty {
                            if reff.mutable && !reff.pinned {
                                if let Type::Ident(ident) = &reff.inner {
                                    insist_extern_types_are_trivial(ident, reason);
                                }
                            }
                        }
                    }
                }
                _ => {}
            }
        }

        let mut types = Types {
            all,
            structs,
            enums,
            cxx,
            rust,
            aliases,
            untrusted,
            required_trivial,
            explicit_impls,
            resolutions,
            struct_improper_ctypes,
            toposorted_structs,
        };

        types.toposorted_structs = toposort::sort(cx, apis, &types);

        let mut unresolved_structs: Vec<&Ident> = types.structs.keys().copied().collect();
        let mut new_information = true;
        while new_information {
            new_information = false;
            unresolved_structs.retain(|ident| {
                let mut retain = false;
                for var in &types.structs[ident].fields {
                    if match types.determine_improper_ctype(&var.ty) {
                        ImproperCtype::Depends(inner) => {
                            retain = true;
                            types.struct_improper_ctypes.contains(inner)
                        }
                        ImproperCtype::Definite(improper) => improper,
                    } {
                        types.struct_improper_ctypes.insert(ident);
                        new_information = true;
                        return false;
                    }
                }
                // If all fields definite false, remove from unresolved_structs.
                retain
            });
        }

        types
    }

    pub fn needs_indirect_abi(&self, ty: &Type) -> bool {
        match ty {
            Type::RustBox(_) | Type::UniquePtr(_) => false,
            Type::Array(_) => true,
            _ => !self.is_guaranteed_pod(ty),
        }
    }

    // Types that trigger rustc's default #[warn(improper_ctypes)] lint, even if
    // they may be otherwise unproblematic to mention in an extern signature.
    // For example in a signature like `extern "C" fn(*const String)`, rustc
    // refuses to believe that C could know how to supply us with a pointer to a
    // Rust String, even though C could easily have obtained that pointer
    // legitimately from a Rust call.
    pub fn is_considered_improper_ctype(&self, ty: &Type) -> bool {
        match self.determine_improper_ctype(ty) {
            ImproperCtype::Definite(improper) => improper,
            ImproperCtype::Depends(ident) => self.struct_improper_ctypes.contains(ident),
        }
    }

    pub fn resolve(&self, ident: &RustName) -> &Pair {
        self.resolutions.get(ident).expect("Unable to resolve type")
    }
}

impl<'t, 'a> IntoIterator for &'t Types<'a> {
    type Item = &'a Type;
    type IntoIter = crate::syntax::set::Iter<'t, 'a, Type>;
    fn into_iter(self) -> Self::IntoIter {
        self.all.into_iter()
    }
}

#[derive(Copy, Clone)]
pub enum TrivialReason<'a> {
    StructField(&'a Struct),
    FunctionArgument(&'a ExternFn),
    FunctionReturn(&'a ExternFn),
    BoxTarget,
    VecElement,
    UnpinnedMutArg(&'a ExternFn),
}

impl<'a> TrivialReason<'a> {
    pub fn describe_in_context(&self, ety: &ExternType) -> String {
        match self {
            TrivialReason::BoxTarget => format!("Box<{}>", ety.name.rust),
            TrivialReason::VecElement => format!("a vector element in Vec<{}>", ety.name.rust),
            _ => self.to_string(),
        }
    }
}

impl<'a> Display for TrivialReason<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            TrivialReason::StructField(strct) => write!(f, "a field of `{}`", strct.name.rust),
            TrivialReason::FunctionArgument(efn) => write!(f, "an argument of `{}`", efn.name.rust),
            TrivialReason::FunctionReturn(efn) => {
                write!(f, "a return value of `{}`", efn.name.rust)
            }
            TrivialReason::BoxTarget => write!(f, "in a Box<...>"),
            TrivialReason::VecElement => write!(f, "a Vec<...> element"),
            TrivialReason::UnpinnedMutArg(efn) => write!(
                f,
                "a non-pinned mutable reference argument of {}",
                efn.name.rust
            ),
        }
    }
}

fn duplicate_name(cx: &mut Errors, sp: impl ToTokens, ident: &Ident) {
    let msg = format!("the name `{}` is defined multiple times", ident);
    cx.error(sp, msg);
}
<commit_msg>Rearrange trivial reason detection<commit_after>use crate::syntax::improper::ImproperCtype;
use crate::syntax::report::Errors;
use crate::syntax::set::{OrderedSet as Set, UnorderedSet};
use crate::syntax::{
    toposort, Api, Enum, ExternFn, ExternType, Impl, Pair, RustName, Struct, Type, TypeAlias,
};
use proc_macro2::Ident;
use quote::ToTokens;
use std::collections::BTreeMap as Map;
use std::fmt::Display;

pub struct Types<'a> {
    pub all: Set<&'a Type>,
    pub structs: Map<&'a Ident, &'a Struct>,
    pub enums: Map<&'a Ident, &'a Enum>,
    pub cxx: Set<&'a Ident>,
    pub rust: Set<&'a Ident>,
    pub aliases: Map<&'a Ident, &'a TypeAlias>,
    pub untrusted: Map<&'a Ident, &'a ExternType>,
    pub required_trivial: Map<&'a Ident, Vec<TrivialReason<'a>>>,
    pub explicit_impls: Set<&'a Impl>,
    pub resolutions: Map<&'a RustName, &'a Pair>,
    pub struct_improper_ctypes: UnorderedSet<&'a Ident>,
    pub toposorted_structs: Vec<&'a Struct>,
}

impl<'a> Types<'a> {
    pub fn collect(cx: &mut Errors, apis: &'a [Api]) -> Self {
        let mut all = Set::new();
        let mut structs = Map::new();
        let mut enums = Map::new();
        let mut cxx = Set::new();
        let mut rust = Set::new();
        let mut aliases = Map::new();
        let mut untrusted = Map::new();
        let mut explicit_impls = Set::new();
        let mut resolutions = Map::new();
        let struct_improper_ctypes = UnorderedSet::new();
        let toposorted_structs = Vec::new();

        fn visit<'a>(all: &mut Set<&'a Type>, ty: &'a Type) {
            all.insert(ty);
            match ty {
                Type::Ident(_) | Type::Str(_) | Type::Void(_) => {}
                Type::RustBox(ty)
                | Type::UniquePtr(ty)
                | Type::SharedPtr(ty)
                | Type::CxxVector(ty)
                | Type::RustVec(ty) => visit(all, &ty.inner),
                Type::Ref(r) => visit(all, &r.inner),
                Type::Array(a) => visit(all, &a.inner),
                Type::SliceRef(s) => visit(all, &s.inner),
                Type::Fn(f) => {
                    if let Some(ret) = &f.ret {
                        visit(all, ret);
                    }
                    for arg in &f.args {
                        visit(all, &arg.ty);
                    }
                }
            }
        }

        let mut add_resolution = |pair: &'a Pair| {
            resolutions.insert(RustName::from_ref(&pair.rust), pair);
        };

        let mut type_names = UnorderedSet::new();
        let mut function_names = UnorderedSet::new();
        for api in apis {
            // The same identifier is permitted to be declared as both a shared
            // enum and extern C++ type, or shared struct and extern C++ type.
            // That indicates to not emit the C++ enum/struct definition because
            // it's defined by the included headers already.
            //
            // All other cases of duplicate identifiers are reported as an error.
            match api {
                Api::Include(_) => {}
                Api::Struct(strct) => {
                    let ident = &strct.name.rust;
                    if !type_names.insert(ident)
                        && (!cxx.contains(ident)
                            || structs.contains_key(ident)
                            || enums.contains_key(ident))
                    {
                        // If already declared as a struct or enum, or if
                        // colliding with something other than an extern C++
                        // type, then error.
                        duplicate_name(cx, strct, ident);
                    }
                    structs.insert(&strct.name.rust, strct);
                    for field in &strct.fields {
                        visit(&mut all, &field.ty);
                    }
                    add_resolution(&strct.name);
                }
                Api::Enum(enm) => {
                    all.insert(&enm.repr_type);
                    let ident = &enm.name.rust;
                    if !type_names.insert(ident)
                        && (!cxx.contains(ident)
                            || structs.contains_key(ident)
                            || enums.contains_key(ident))
                    {
                        // If already declared as a struct or enum, or if
                        // colliding with something other than an extern C++
                        // type, then error.
                        duplicate_name(cx, enm, ident);
                    }
                    enums.insert(ident, enm);
                    add_resolution(&enm.name);
                }
                Api::CxxType(ety) => {
                    let ident = &ety.name.rust;
                    if !type_names.insert(ident)
                        && (cxx.contains(ident)
                            || !structs.contains_key(ident) && !enums.contains_key(ident))
                    {
                        // If already declared as an extern C++ type, or if
                        // colliding with something which is neither struct nor
                        // enum, then error.
                        duplicate_name(cx, ety, ident);
                    }
                    cxx.insert(ident);
                    if !ety.trusted {
                        untrusted.insert(ident, ety);
                    }
                    add_resolution(&ety.name);
                }
                Api::RustType(ety) => {
                    let ident = &ety.name.rust;
                    if !type_names.insert(ident) {
                        duplicate_name(cx, ety, ident);
                    }
                    rust.insert(ident);
                    add_resolution(&ety.name);
                }
                Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                    // Note: duplication of the C++ name is fine because C++ has
                    // function overloading.
                    if !function_names.insert((&efn.receiver, &efn.name.rust)) {
                        duplicate_name(cx, efn, &efn.name.rust);
                    }
                    for arg in &efn.args {
                        visit(&mut all, &arg.ty);
                    }
                    if let Some(ret) = &efn.ret {
                        visit(&mut all, ret);
                    }
                }
                Api::TypeAlias(alias) => {
                    let ident = &alias.name.rust;
                    if !type_names.insert(ident) {
                        duplicate_name(cx, alias, ident);
                    }
                    cxx.insert(ident);
                    aliases.insert(ident, alias);
                    add_resolution(&alias.name);
                }
                Api::Impl(imp) => {
                    visit(&mut all, &imp.ty);
                    explicit_impls.insert(imp);
                }
            }
        }

        // All these APIs may contain types passed by value. We need to ensure
        // we check that this is permissible. We do this _after_ scanning all
        // the APIs above, in case some function or struct references a type
        // which is declared subsequently.
        let mut required_trivial: Map<_, Vec<_>> = Map::new();

        let mut insist_extern_types_are_trivial = |ident: &'a RustName, reason| {
            if cxx.contains(&ident.rust)
                && !structs.contains_key(&ident.rust)
                && !enums.contains_key(&ident.rust)
            {
                required_trivial
                    .entry(&ident.rust)
                    .or_default()
                    .push(reason);
            }
        };
        for api in apis {
            match api {
                Api::Struct(strct) => {
                    for field in &strct.fields {
                        if let Type::Ident(ident) = &field.ty {
                            let reason = TrivialReason::StructField(strct);
                            insist_extern_types_are_trivial(ident, reason);
                        }
                    }
                }
                Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                    for arg in &efn.args {
                        if let Type::Ident(ident) = &arg.ty {
                            let reason = TrivialReason::FunctionArgument(efn);
                            insist_extern_types_are_trivial(ident, reason);
                        }
                    }
                    if let Some(ret) = &efn.ret {
                        if let Type::Ident(ident) = &ret {
                            let reason = TrivialReason::FunctionReturn(efn);
                            insist_extern_types_are_trivial(ident, reason);
                        }
                    }
                }
                _ => {}
            }
        }
        for ty in &all {
            match ty {
                Type::RustBox(ty) => {
                    if let Type::Ident(ident) = &ty.inner {
                        let reason = TrivialReason::BoxTarget;
                        insist_extern_types_are_trivial(ident, reason);
                    }
                }
                Type::RustVec(ty) => {
                    if let Type::Ident(ident) = &ty.inner {
                        let reason = TrivialReason::VecElement;
                        insist_extern_types_are_trivial(ident, reason);
                    }
                }
                _ => {}
            }
        }
        for api in apis {
            match api {
                Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                    if let Some(receiver) = &efn.receiver {
                        if receiver.mutable && !receiver.pinned {
                            let reason = TrivialReason::UnpinnedMutArg(efn);
                            insist_extern_types_are_trivial(&receiver.ty, reason);
                        }
                    }
                    for arg in &efn.args {
                        if let Type::Ref(reff) = &arg.ty {
                            if reff.mutable && !reff.pinned {
                                if let Type::Ident(ident) = &reff.inner {
                                    let reason = TrivialReason::UnpinnedMutArg(efn);
                                    insist_extern_types_are_trivial(ident, reason);
                                }
                            }
                        }
                    }
                }
                _ => {}
            }
        }

        let mut types = Types {
            all,
            structs,
            enums,
            cxx,
            rust,
            aliases,
            untrusted,
            required_trivial,
            explicit_impls,
            resolutions,
            struct_improper_ctypes,
            toposorted_structs,
        };

        types.toposorted_structs = toposort::sort(cx, apis, &types);

        let mut unresolved_structs: Vec<&Ident> = types.structs.keys().copied().collect();
        let mut new_information = true;
        while new_information {
            new_information = false;
            unresolved_structs.retain(|ident| {
                let mut retain = false;
                for var in &types.structs[ident].fields {
                    if match types.determine_improper_ctype(&var.ty) {
                        ImproperCtype::Depends(inner) => {
                            retain = true;
                            types.struct_improper_ctypes.contains(inner)
                        }
                        ImproperCtype::Definite(improper) => improper,
                    } {
                        types.struct_improper_ctypes.insert(ident);
                        new_information = true;
                        return false;
                    }
                }
                // If all fields definite false, remove from unresolved_structs.
                retain
            });
        }

        types
    }

    pub fn needs_indirect_abi(&self, ty: &Type) -> bool {
        match ty {
            Type::RustBox(_) | Type::UniquePtr(_) => false,
            Type::Array(_) => true,
            _ => !self.is_guaranteed_pod(ty),
        }
    }

    // Types that trigger rustc's default #[warn(improper_ctypes)] lint, even if
    // they may be otherwise unproblematic to mention in an extern signature.
    // For example in a signature like `extern "C" fn(*const String)`, rustc
    // refuses to believe that C could know how to supply us with a pointer to a
    // Rust String, even though C could easily have obtained that pointer
    // legitimately from a Rust call.
    pub fn is_considered_improper_ctype(&self, ty: &Type) -> bool {
        match self.determine_improper_ctype(ty) {
            ImproperCtype::Definite(improper) => improper,
            ImproperCtype::Depends(ident) => self.struct_improper_ctypes.contains(ident),
        }
    }

    pub fn resolve(&self, ident: &RustName) -> &Pair {
        self.resolutions.get(ident).expect("Unable to resolve type")
    }
}

impl<'t, 'a> IntoIterator for &'t Types<'a> {
    type Item = &'a Type;
    type IntoIter = crate::syntax::set::Iter<'t, 'a, Type>;
    fn into_iter(self) -> Self::IntoIter {
        self.all.into_iter()
    }
}

#[derive(Copy, Clone)]
pub enum TrivialReason<'a> {
    StructField(&'a Struct),
    FunctionArgument(&'a ExternFn),
    FunctionReturn(&'a ExternFn),
    BoxTarget,
    VecElement,
    UnpinnedMutArg(&'a ExternFn),
}

impl<'a> TrivialReason<'a> {
    pub fn describe_in_context(&self, ety: &ExternType) -> String {
        match self {
            TrivialReason::BoxTarget => format!("Box<{}>", ety.name.rust),
            TrivialReason::VecElement => format!("a vector element in Vec<{}>", ety.name.rust),
            _ => self.to_string(),
        }
    }
}

impl<'a> Display for TrivialReason<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            TrivialReason::StructField(strct) => write!(f, "a field of `{}`", strct.name.rust),
            TrivialReason::FunctionArgument(efn) => write!(f, "an argument of `{}`", efn.name.rust),
            TrivialReason::FunctionReturn(efn) => {
                write!(f, "a return value of `{}`", efn.name.rust)
            }
            TrivialReason::BoxTarget => write!(f, "in a Box<...>"),
            TrivialReason::VecElement => write!(f, "a Vec<...> element"),
            TrivialReason::UnpinnedMutArg(efn) => write!(
                f,
                "a non-pinned mutable reference argument of {}",
                efn.name.rust
            ),
        }
    }
}

fn duplicate_name(cx: &mut Errors, sp: impl ToTokens, ident: &Ident) {
    let msg = format!("the name `{}` is defined multiple times", ident);
    cx.error(sp, msg);
}
<|endoftext|>


<commit_before>extern crate session_types;
extern crate rand;

use session_types::*;
use std::sync::mpsc::{channel, Receiver};
use std::thread::spawn;
use rand::random;

type Server = Recv<u8, Choose<Send<u8, Eps>, Eps>>;
type Client = <Server as HasDual>::Dual;

fn handler(c: Chan<(), Server>) {
    let (c, n) = c.recv();
    match n.checked_add(42) {
        Some(n) => c.sel1().send(n).close(),
        None => c.sel2().close(),
    }
}

fn server(rx: Receiver<Chan<(), Server>>) {
    let mut count = 0;
    loop {
        match borrow_request(&rx) {
            Some(c) => {
                spawn(move || handler(c));
                count += 1;
            },
            None => break,
        }
    }
    println!("Handled {} connections", count);
}

fn client(c: Chan<(), Client>) {
    let n = random();
    match c.send(n).offer() {
        Ok(c) => {
            let (c, n2) = c.recv();
            c.close();
            println!("{} + 42 = {}", n, n2);
        },
        Err(c) => {
            c.close();
            println!("{} + 42 is an overflow :(", n);
        }
    }
}

fn main() {
    let (tx, rx) = channel();
    let mut buf = Vec::new();

    let n: u8 = random();
    println!("Spawning {} clients", n);
    for _ in 0..n {
        let tmp = tx.clone();
        buf.push(spawn(move || client(accept(tmp).unwrap())));
    }
    drop(tx);

    server(rx);
    for t in buf {
        t.join().unwrap();
    }
}
<commit_msg>We dont need to join if `server` isn't spawned<commit_after>extern crate session_types;
extern crate rand;

use session_types::*;
use std::sync::mpsc::{channel, Receiver};
use std::thread::spawn;
use rand::random;

type Server = Recv<u8, Choose<Send<u8, Eps>, Eps>>;
type Client = <Server as HasDual>::Dual;

fn handler(c: Chan<(), Server>) {
    let (c, n) = c.recv();
    match n.checked_add(42) {
        Some(n) => c.sel1().send(n).close(),
        None => c.sel2().close(),
    }
}

fn server(rx: Receiver<Chan<(), Server>>) {
    let mut count = 0;
    loop {
        match borrow_request(&rx) {
            Some(c) => {
                spawn(move || handler(c));
                count += 1;
            },
            None => break,
        }
    }
    println!("Handled {} connections", count);
}

fn client(c: Chan<(), Client>) {
    let n = random();
    match c.send(n).offer() {
        Ok(c) => {
            let (c, n2) = c.recv();
            c.close();
            println!("{} + 42 = {}", n, n2);
        },
        Err(c) => {
            c.close();
            println!("{} + 42 is an overflow :(", n);
        }
    }
}

fn main() {
    let (tx, rx) = channel();
    let mut buf = Vec::new();

    let n: u8 = random();
    println!("Spawning {} clients", n);
    for _ in 0..n {
        let tmp = tx.clone();
        buf.push(spawn(move || client(accept(tmp).unwrap())));
    }
    drop(tx);

    server(rx);
}
<|endoftext|>


<commit_before>// A port of the simplistic benchmark from
//
//    http://github.com/PaulKeeble/ScalaVErlangAgents
//
// I *think* it's the same, more or less.

#![crate_name = "msgsend"]

extern crate time;
extern crate zmq;

use std::task::TaskBuilder;
use std::comm;
use std::os;

fn server(mut pull_socket: zmq::Socket, mut push_socket: zmq::Socket, mut workers: uint) {
    let mut count = 0u;
    let mut msg = zmq::Message::new().unwrap();

    while workers != 0 {
        match pull_socket.recv(&mut msg, 0) {
            Err(e) => panic!(e.to_string()),
            Ok(()) => {
                let s = msg.as_str().unwrap();
                if s.is_empty() {
                    workers -= 1;
                } else {
                    count += from_str::<uint>(s).unwrap();
                }
            }
        }
    }

    match push_socket.send_str(count.to_string().as_slice(), 0) {
        Ok(()) => { }
        Err(e) => panic!(e.to_string()),
    }
}

fn spawn_server(ctx: &mut zmq::Context, workers: uint) -> comm::Sender<()> {
    let mut pull_socket = ctx.socket(zmq::PULL).unwrap();
    let mut push_socket = ctx.socket(zmq::PUSH).unwrap();

    pull_socket.bind("inproc://server-pull").unwrap();
    push_socket.bind("inproc://server-push").unwrap();

    // Spawn the server.
    let (ready_tx, ready_rx) = comm::channel();
    let (start_tx, start_rx) = comm::channel();

    // Mutable sockets cannot be implicitly captured.
    let pull_socket = pull_socket;
    let push_socket = push_socket;

    TaskBuilder::new().spawn(proc() {
        // Let the main thread know we're ready.
        ready_tx.send(());

        // Wait until we need to start.
        start_rx.recv();

        server(pull_socket, push_socket, workers);
    });

    // Wait for the server to start.
    ready_rx.recv();

    start_tx
}

fn worker(mut push_socket: zmq::Socket, count: uint) {
    for _ in range(0, count) {
        push_socket.send_str(100u.to_string().as_slice(), 0).unwrap();
    }

    // Let the server know we're done.
    push_socket.send_str("", 0).unwrap();
}

fn spawn_worker(ctx: &mut zmq::Context, count: uint) -> comm::Receiver<()> {
    let mut push_socket = ctx.socket(zmq::PUSH).unwrap();

    push_socket.connect("inproc://server-pull").unwrap();
    //push_socket.connect("tcp://127.0.0.1:3456").unwrap();

    // Mutable sockets cannot be implicitly captured.
    let push_socket = push_socket;

    // Spawn the worker.
    let (tx, rx) = comm::channel();
    TaskBuilder::new().spawn(proc() {
        // Let the main thread we're ready.
        tx.send(());

        worker(push_socket, count);

        tx.send(());
    });

    // Wait for the worker to start.
    rx.recv();

    rx
}

fn run(ctx: &mut zmq::Context, size: uint, workers: uint) {
    let start_ch = spawn_server(ctx, workers);

    // Create some command/control sockets.
    let mut push_socket = ctx.socket(zmq::PUSH).unwrap();
    let mut pull_socket = ctx.socket(zmq::PULL).unwrap();

    push_socket.connect("inproc://server-pull").unwrap();
    pull_socket.connect("inproc://server-push").unwrap();
    //push_socket.connect("tcp://127.0.0.1:3456").unwrap();
    //pull_socket.connect("tcp://127.0.0.1:3457").unwrap();

    // Spawn all the workers.
    let mut worker_results = Vec::new();
    for _ in range(0, workers) {
        worker_results.push(spawn_worker(ctx, size / workers));
    }

    let start = time::precise_time_s();

    start_ch.send(());

    // Block until all the workers finish.
    for po in worker_results.iter() {
        po.recv();
    }

    // Receive the final count.
    let result = match pull_socket.recv_msg(0) {
        Ok(msg) => from_str::<uint>(msg.as_str().unwrap()).unwrap(),
        Err(e) => panic!(e.to_string()),
    };

    let end = time::precise_time_s();
    let elapsed = end - start;

    println!("Count is {}", result);
    println!("Test took {} seconds", elapsed);
    let thruput = ((size / workers * workers) as f64) / elapsed;
    println!("Throughput={} per sec", thruput);
}

fn main() {
    let args = os::args();

    let args = if os::getenv("RUST_BENCH").is_some() {
        vec!("".to_string(), "1000000".to_string(), "10000".to_string())
    } else if args.len() <= 1u {
        vec!("".to_string(), "10000".to_string(), "4".to_string())
    } else {
        args
    };

    let size: uint = from_str(args[1].as_slice()).unwrap();
    let workers: uint = from_str(args[2].as_slice()).unwrap();

    let mut ctx = zmq::Context::new();

    run(&mut ctx, size, workers);
}
<commit_msg>Remove workaround no longer necessary<commit_after>// A port of the simplistic benchmark from
//
//    http://github.com/PaulKeeble/ScalaVErlangAgents
//
// I *think* it's the same, more or less.

#![crate_name = "msgsend"]

extern crate time;
extern crate zmq;

use std::task::TaskBuilder;
use std::comm;
use std::os;

fn server(mut pull_socket: zmq::Socket, mut push_socket: zmq::Socket, mut workers: uint) {
    let mut count = 0u;
    let mut msg = zmq::Message::new().unwrap();

    while workers != 0 {
        match pull_socket.recv(&mut msg, 0) {
            Err(e) => panic!(e.to_string()),
            Ok(()) => {
                let s = msg.as_str().unwrap();
                if s.is_empty() {
                    workers -= 1;
                } else {
                    count += from_str::<uint>(s).unwrap();
                }
            }
        }
    }

    match push_socket.send_str(count.to_string().as_slice(), 0) {
        Ok(()) => { }
        Err(e) => panic!(e.to_string()),
    }
}

fn spawn_server(ctx: &mut zmq::Context, workers: uint) -> comm::Sender<()> {
    let mut pull_socket = ctx.socket(zmq::PULL).unwrap();
    let mut push_socket = ctx.socket(zmq::PUSH).unwrap();

    pull_socket.bind("inproc://server-pull").unwrap();
    push_socket.bind("inproc://server-push").unwrap();

    // Spawn the server.
    let (ready_tx, ready_rx) = comm::channel();
    let (start_tx, start_rx) = comm::channel();

    TaskBuilder::new().spawn(proc() {
        // Let the main thread know we're ready.
        ready_tx.send(());

        // Wait until we need to start.
        start_rx.recv();

        server(pull_socket, push_socket, workers);
    });

    // Wait for the server to start.
    ready_rx.recv();

    start_tx
}

fn worker(mut push_socket: zmq::Socket, count: uint) {
    for _ in range(0, count) {
        push_socket.send_str(100u.to_string().as_slice(), 0).unwrap();
    }

    // Let the server know we're done.
    push_socket.send_str("", 0).unwrap();
}

fn spawn_worker(ctx: &mut zmq::Context, count: uint) -> comm::Receiver<()> {
    let mut push_socket = ctx.socket(zmq::PUSH).unwrap();

    push_socket.connect("inproc://server-pull").unwrap();
    //push_socket.connect("tcp://127.0.0.1:3456").unwrap();

    // Spawn the worker.
    let (tx, rx) = comm::channel();
    TaskBuilder::new().spawn(proc() {
        // Let the main thread we're ready.
        tx.send(());

        worker(push_socket, count);

        tx.send(());
    });

    // Wait for the worker to start.
    rx.recv();

    rx
}

fn run(ctx: &mut zmq::Context, size: uint, workers: uint) {
    let start_ch = spawn_server(ctx, workers);

    // Create some command/control sockets.
    let mut push_socket = ctx.socket(zmq::PUSH).unwrap();
    let mut pull_socket = ctx.socket(zmq::PULL).unwrap();

    push_socket.connect("inproc://server-pull").unwrap();
    pull_socket.connect("inproc://server-push").unwrap();
    //push_socket.connect("tcp://127.0.0.1:3456").unwrap();
    //pull_socket.connect("tcp://127.0.0.1:3457").unwrap();

    // Spawn all the workers.
    let mut worker_results = Vec::new();
    for _ in range(0, workers) {
        worker_results.push(spawn_worker(ctx, size / workers));
    }

    let start = time::precise_time_s();

    start_ch.send(());

    // Block until all the workers finish.
    for po in worker_results.iter() {
        po.recv();
    }

    // Receive the final count.
    let result = match pull_socket.recv_msg(0) {
        Ok(msg) => from_str::<uint>(msg.as_str().unwrap()).unwrap(),
        Err(e) => panic!(e.to_string()),
    };

    let end = time::precise_time_s();
    let elapsed = end - start;

    println!("Count is {}", result);
    println!("Test took {} seconds", elapsed);
    let thruput = ((size / workers * workers) as f64) / elapsed;
    println!("Throughput={} per sec", thruput);
}

fn main() {
    let args = os::args();

    let args = if os::getenv("RUST_BENCH").is_some() {
        vec!("".to_string(), "1000000".to_string(), "10000".to_string())
    } else if args.len() <= 1u {
        vec!("".to_string(), "10000".to_string(), "4".to_string())
    } else {
        args
    };

    let size: uint = from_str(args[1].as_slice()).unwrap();
    let workers: uint = from_str(args[2].as_slice()).unwrap();

    let mut ctx = zmq::Context::new();

    run(&mut ctx, size, workers);
}
<|endoftext|>