<commit_before>use events::{Event, EventHandler};
use formatter::formatter::Formatter;
use runner;
use std::io;

pub struct Simple<'a, Io: io::Write + 'a> {
    buf: &'a mut Io
}

impl<'a, T : io::Write> Simple<'a, T> {
    fn new<'b>(buf: &'b mut T) -> Simple<'b, T> {
        Simple { buf: buf }
    }

    fn write_summary(&mut self, result: runner::RunnerResult) -> Result<(), io::Error> {
        let (res, report) = match result {
            Ok(report) => ("ok", report),
            Err(report) => ("FAILED", report)
        };

        writeln!(
            self.buf,
            "test result: {}. {} examples; {} passed; {} failed;",
            res,
            report.total_tests,
            report.success_count,
            report.error_count
        )
    }
}

impl<'a, T : io::Write> EventHandler for Simple<'a, T> {
    fn trigger(&mut self, event: Event) {
        // FIXME: do something with the io::Error ?
        let _ = match event {
            Event::StartRunner => writeln!(self.buf, "Running tests..."),
            Event::FinishedRunner(result) => self.write_summary(result)
        };
    }
}
impl<'a, T : io::Write> Formatter for Simple<'a, T> {}

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

    #[test]
    fn it_can_be_instanciated() {
        Simple::new(&mut vec!(1u8));
    }

    #[test]
    fn it_impl_formatter_trait() {
        let _ : &Formatter = &Simple::new(&mut vec!(1u8)) as &Formatter;
    }

    #[cfg(test)]
    mod event_start_runner {
        pub use super::*;
        use events::{Event, EventHandler};
        use std::str;

        #[test]
        fn it_display_that_tests_started() {
            let mut v = vec!();
            {
                let mut s = Simple::new(&mut v);
                s.trigger(Event::StartRunner);
            }

            assert_eq!("Running tests...\n", str::from_utf8(&v).unwrap());
        }
    }

    #[cfg(test)]
    mod event_finished_runner {
        pub use super::*;
        use events::{Event, EventHandler};
        use runner::TestReport;
        use std::str;

        fn make_report(succes: u32, errors: u32) -> Result<TestReport, TestReport> {
            let mut report = TestReport::default();
            report.success_count = succes;
            report.error_count = errors;
            report.total_tests = succes + errors;

            if errors != 0 {
                Err(report)
            } else {
                Ok(report)
            }
        }

        macro_rules! test_and_compare_output {
            ($(
                $test_name:ident : (success: $succ:expr, errors: $err:expr) => $msg:expr
            ),+) => {

                $(
                    #[test]
                    fn $test_name() {
                        let mut v = vec!();
                        {
                            let mut s = Simple::new(&mut v);
                            s.trigger(Event::FinishedRunner(make_report($succ, $err)))
                        }

                        assert_eq!($msg, str::from_utf8(&v).unwrap())
                    }
                )+
            }
        }

        test_and_compare_output! {
            no_test_is_ok: (success: 0, errors: 0) =>
                "test result: ok. 0 examples; 0 passed; 0 failed;\n",
            one_test: (success: 1, errors: 0) =>
                "test result: ok. 1 examples; 1 passed; 0 failed;\n",
            multiple_ok: (success: 42, errors: 0) =>
                "test result: ok. 42 examples; 42 passed; 0 failed;\n",
            one_error: (success: 0, errors: 1) =>
              "test result: FAILED. 1 examples; 0 passed; 1 failed;\n",
            multiple_errors: (success: 0, errors: 37) =>
              "test result: FAILED. 37 examples; 0 passed; 37 failed;\n"
        }
    }
}
<commit_msg> add some examples<commit_after>use events::{Event, EventHandler};
use formatter::formatter::Formatter;
use runner;
use std::io;

pub struct Simple<'a, Io: io::Write + 'a> {
    buf: &'a mut Io
}

impl<'a, T : io::Write> Simple<'a, T> {
    fn new<'b>(buf: &'b mut T) -> Simple<'b, T> {
        Simple { buf: buf }
    }

    fn write_summary(&mut self, result: runner::RunnerResult) -> Result<(), io::Error> {
        let (res, report) = match result {
            Ok(report) => ("ok", report),
            Err(report) => ("FAILED", report)
        };

        writeln!(
            self.buf,
            "test result: {}. {} examples; {} passed; {} failed;",
            res,
            report.total_tests,
            report.success_count,
            report.error_count
        )
    }
}

impl<'a, T : io::Write> EventHandler for Simple<'a, T> {
    fn trigger(&mut self, event: Event) {
        // FIXME: do something with the io::Error ?
        let _ = match event {
            Event::StartRunner => writeln!(self.buf, "Running tests..."),
            Event::FinishedRunner(result) => self.write_summary(result)
        };
    }
}
impl<'a, T : io::Write> Formatter for Simple<'a, T> {}

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

    #[test]
    fn it_can_be_instanciated() {
        Simple::new(&mut vec!(1u8));
    }

    #[test]
    fn it_impl_formatter_trait() {
        let _ : &Formatter = &Simple::new(&mut vec!(1u8)) as &Formatter;
    }

    #[cfg(test)]
    mod event_start_runner {
        pub use super::*;
        use events::{Event, EventHandler};
        use std::str;

        #[test]
        fn it_display_that_tests_started() {
            let mut v = vec!();
            {
                let mut s = Simple::new(&mut v);
                s.trigger(Event::StartRunner);
            }

            assert_eq!("Running tests...\n", str::from_utf8(&v).unwrap());
        }
    }

    #[cfg(test)]
    mod event_finished_runner {
        pub use super::*;
        use events::{Event, EventHandler};
        use runner::TestReport;
        use std::str;

        fn make_report(succes: u32, errors: u32) -> Result<TestReport, TestReport> {
            let mut report = TestReport::default();
            report.success_count = succes;
            report.error_count = errors;
            report.total_tests = succes + errors;

            if errors != 0 {
                Err(report)
            } else {
                Ok(report)
            }
        }

        macro_rules! test_and_compare_output {
            ($(
                $test_name:ident : (success: $succ:expr, errors: $err:expr) => $msg:expr
            ),+) => {

                $(
                    #[test]
                    fn $test_name() {
                        let mut v = vec!();
                        {
                            let mut s = Simple::new(&mut v);
                            s.trigger(Event::FinishedRunner(make_report($succ, $err)))
                        }

                        assert_eq!($msg, str::from_utf8(&v).unwrap())
                    }
                )+
            }
        }

        test_and_compare_output! {
            no_test_is_ok: (success: 0, errors: 0) =>
                "test result: ok. 0 examples; 0 passed; 0 failed;\n",
            one_test: (success: 1, errors: 0) =>
                "test result: ok. 1 examples; 1 passed; 0 failed;\n",
            multiple_ok: (success: 42, errors: 0) =>
                "test result: ok. 42 examples; 42 passed; 0 failed;\n",
            one_error: (success: 0, errors: 1) =>
              "test result: FAILED. 1 examples; 0 passed; 1 failed;\n",
            multiple_errors: (success: 0, errors: 37) =>
              "test result: FAILED. 37 examples; 0 passed; 37 failed;\n",
            one_of_each: (success: 1, errors: 1) =>
              "test result: FAILED. 2 examples; 1 passed; 1 failed;\n",
            multiple_of_each: (success: 12, errors: 21) =>
              "test result: FAILED. 33 examples; 12 passed; 21 failed;\n"
        }
    }
}
<|endoftext|>


<commit_before>//! Use this module to interact with Gdax through a Generic API.
//! This a more convenient and safe way to deal with the exchange since methods return a Result<>
//! but this generic API does not provide all the functionnality that Gdax offers.

use exchange::ExchangeApi;
use gdax::api::GdaxApi;
use gdax::utils;

use error::*;
use types::*;
use helpers;

impl ExchangeApi for GdaxApi {
    fn ticker(&mut self, pair: Pair) -> Result<Ticker> {

        let result = self.return_ticker(pair)?;

        let price = helpers::from_json_bigdecimal(&result["price"], "price")?;
        let ask = helpers::from_json_bigdecimal(&result["ask"], "ask")?;
        let bid = helpers::from_json_bigdecimal(&result["bid"], "bid")?;
        let vol = helpers::from_json_bigdecimal(&result["size"], "size")?;

        Ok(Ticker {
               timestamp: helpers::get_unix_timestamp_ms(),
               pair,
               last_trade_price: price,
               lowest_ask: ask,
               highest_bid: bid,
               volume: Some(vol),
           })
    }

    fn orderbook(&mut self, pair: Pair) -> Result<Orderbook> {

        let raw_response = self.return_order_book(pair)?;

        let result = utils::parse_result(&raw_response)?;

        let mut ask_offers = Vec::new();
        let mut bid_offers = Vec::new();

        let ask_array =
            result["asks"]
                .as_array()
                .ok_or_else(|| ErrorKind::InvalidFieldFormat(format!("{}", result["asks"])))?;
        let bid_array =
            result["bids"]
                .as_array()
                .ok_or_else(|| ErrorKind::InvalidFieldFormat(format!("{}", result["asks"])))?;

        for ask in ask_array {
            let price = helpers::from_json_bigdecimal(&ask[0], "ask price")?;
            let volume = helpers::from_json_bigdecimal(&ask[1], "ask volume")?;

            ask_offers.push((price, volume));
        }

        for bid in bid_array {
            let price = helpers::from_json_bigdecimal(&bid[0], "bid price")?;
            let volume = helpers::from_json_bigdecimal(&bid[1], "bid volume")?;

            bid_offers.push((price, volume));
        }

        Ok(Orderbook {
            timestamp: helpers::get_unix_timestamp_ms(),
            pair: pair,
            asks: ask_offers,
            bids: bid_offers,
        })
    }

    fn add_order(&mut self,
                 order_type: OrderType,
                 pair: Pair,
                 quantity: Volume,
                 price: Option<Price>)
                 -> Result<OrderInfo> {
        //let pair_name = match utils::get_pair_string(&pair) {
        //Some(name) => name,
        //None => return Err(ErrorKind::PairUnsupported.into()),
        //};

        let result = match order_type {
            OrderType::BuyLimit => {
                if price.is_none() {
                    return Err(ErrorKind::MissingPrice.into());
                }

                // Unwrap safe here with the check above.
                self.buy_limit(pair, quantity, price.unwrap(), None, None)
            }
            OrderType::BuyMarket => self.buy_market(pair, quantity),
            OrderType::SellLimit => {
                if price.is_none() {
                    return Err(ErrorKind::MissingPrice.into());
                }

                // Unwrap safe here with the check above.
                self.sell_limit(pair, quantity, price.unwrap(), None, None)
            }
            OrderType::SellMarket => self.sell_market(pair, quantity),
        };

        Ok(OrderInfo {
               timestamp: helpers::get_unix_timestamp_ms(),
               identifier: vec![result?["id"]
                                    .as_str()
                                    .ok_or_else(|| {
                                                    ErrorKind::MissingField("id".to_string())
                                                })?
                                    .to_string()],
           })
    }

    /// Return the balances for each currency on the account
    fn balances(&mut self) -> Result<Balances> {
        let raw_response = self.return_balances()?;
        let result = utils::parse_result(&raw_response)?;

        let mut balances = Balances::new();

        for (key, val) in result.iter() {
            let currency = utils::get_currency_enum(key);

            match currency {
                Some(c) => {
                    let amount = helpers::from_json_bigdecimal(&val, "amount")?;

                    balances.insert(c, amount);
                },
                _ => ()
            }
        }

        Ok(balances)
    }
}
<commit_msg>When getting the ticker we want the 24h volume, not the specific size of the last transaction. This is what we are getting in the rest of exchanges.<commit_after>//! Use this module to interact with Gdax through a Generic API.
//! This a more convenient and safe way to deal with the exchange since methods return a Result<>
//! but this generic API does not provide all the functionnality that Gdax offers.

use exchange::ExchangeApi;
use gdax::api::GdaxApi;
use gdax::utils;

use error::*;
use types::*;
use helpers;

impl ExchangeApi for GdaxApi {
    fn ticker(&mut self, pair: Pair) -> Result<Ticker> {

        let result = self.return_ticker(pair)?;

        let price = helpers::from_json_bigdecimal(&result["price"], "price")?;
        let ask = helpers::from_json_bigdecimal(&result["ask"], "ask")?;
        let bid = helpers::from_json_bigdecimal(&result["bid"], "bid")?;
        let vol = helpers::from_json_bigdecimal(&result["volume"], "volume")?;

        Ok(Ticker {
               timestamp: helpers::get_unix_timestamp_ms(),
               pair,
               last_trade_price: price,
               lowest_ask: ask,
               highest_bid: bid,
               volume: Some(vol),
           })
    }

    fn orderbook(&mut self, pair: Pair) -> Result<Orderbook> {

        let raw_response = self.return_order_book(pair)?;

        let result = utils::parse_result(&raw_response)?;

        let mut ask_offers = Vec::new();
        let mut bid_offers = Vec::new();

        let ask_array =
            result["asks"]
                .as_array()
                .ok_or_else(|| ErrorKind::InvalidFieldFormat(format!("{}", result["asks"])))?;
        let bid_array =
            result["bids"]
                .as_array()
                .ok_or_else(|| ErrorKind::InvalidFieldFormat(format!("{}", result["asks"])))?;

        for ask in ask_array {
            let price = helpers::from_json_bigdecimal(&ask[0], "ask price")?;
            let volume = helpers::from_json_bigdecimal(&ask[1], "ask volume")?;

            ask_offers.push((price, volume));
        }

        for bid in bid_array {
            let price = helpers::from_json_bigdecimal(&bid[0], "bid price")?;
            let volume = helpers::from_json_bigdecimal(&bid[1], "bid volume")?;

            bid_offers.push((price, volume));
        }

        Ok(Orderbook {
            timestamp: helpers::get_unix_timestamp_ms(),
            pair: pair,
            asks: ask_offers,
            bids: bid_offers,
        })
    }

    fn add_order(&mut self,
                 order_type: OrderType,
                 pair: Pair,
                 quantity: Volume,
                 price: Option<Price>)
                 -> Result<OrderInfo> {
        //let pair_name = match utils::get_pair_string(&pair) {
        //Some(name) => name,
        //None => return Err(ErrorKind::PairUnsupported.into()),
        //};

        let result = match order_type {
            OrderType::BuyLimit => {
                if price.is_none() {
                    return Err(ErrorKind::MissingPrice.into());
                }

                // Unwrap safe here with the check above.
                self.buy_limit(pair, quantity, price.unwrap(), None, None)
            }
            OrderType::BuyMarket => self.buy_market(pair, quantity),
            OrderType::SellLimit => {
                if price.is_none() {
                    return Err(ErrorKind::MissingPrice.into());
                }

                // Unwrap safe here with the check above.
                self.sell_limit(pair, quantity, price.unwrap(), None, None)
            }
            OrderType::SellMarket => self.sell_market(pair, quantity),
        };

        Ok(OrderInfo {
               timestamp: helpers::get_unix_timestamp_ms(),
               identifier: vec![result?["id"]
                                    .as_str()
                                    .ok_or_else(|| {
                                                    ErrorKind::MissingField("id".to_string())
                                                })?
                                    .to_string()],
           })
    }

    /// Return the balances for each currency on the account
    fn balances(&mut self) -> Result<Balances> {
        let raw_response = self.return_balances()?;
        let result = utils::parse_result(&raw_response)?;

        let mut balances = Balances::new();

        for (key, val) in result.iter() {
            let currency = utils::get_currency_enum(key);

            match currency {
                Some(c) => {
                    let amount = helpers::from_json_bigdecimal(&val, "amount")?;

                    balances.insert(c, amount);
                },
                _ => ()
            }
        }

        Ok(balances)
    }
}
<|endoftext|>


<commit_before>use ast::{Literal, Pattern};
use std::cmp::Ordering;
use std::fmt;
use std::mem::transmute;
use std::rc::Rc;
use vm::Vm;

#[derive(Clone, Eq, Debug, PartialEq, PartialOrd, Ord)]
pub enum Op {
    Mul,
    Div,
    Add,
    Sub,
}

pub type NativeCode = *const fn(&mut Vm) -> InstructionSequence;

#[derive(Clone)]
pub struct NativeFunction {
    function: NativeCode,
}

impl NativeFunction {
    pub fn new(f: NativeCode) -> Self {
        NativeFunction { function: f }
    }

    pub fn call(&self, vm: &mut Vm) -> InstructionSequence {
        unsafe {
            let func = transmute::<NativeCode, fn(&mut Vm) -> InstructionSequence>(self.function);
            func(vm)
        }
    }
}

impl PartialEq for NativeFunction {
    fn eq(&self, other: &NativeFunction) -> bool {
        self.function as *const _ == other.function as *const _
    }
}

impl Eq for NativeFunction {}

impl Ord for NativeFunction {
    fn cmp(&self, other: &NativeFunction) -> Ordering {
        (self.function as *const _).cmp(&(other.function as *const _))
    }
}

impl PartialOrd for NativeFunction {
    fn partial_cmp(&self, other: &NativeFunction) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl fmt::Debug for NativeFunction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "NativeFunction")
    }
}

#[derive(Clone, Eq, Debug, PartialEq, PartialOrd, Ord)]
pub enum Instruction {
    Clear,
    Push(Literal),
    Fetch(String),
    LocalAssign(String),
    Assign(String),
    Call(usize),
    MakeMap(usize),
    Rescue(Rc<Pattern>, Rc<InstructionSequence>),
    IndexAccess,
    IndexAssign,
    Raise,
    BinOp(Op),
    Import,
    Native(NativeFunction),
    Nop,
}

pub type InstructionSequence = Vec<Instruction>;

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

    fn mock(_: &mut Vm) -> InstructionSequence {
        vec![]
    }
    fn other_mock(_: &mut Vm) -> InstructionSequence {
        vec![]
    }

    #[test]
    fn compare_native_functions() {
        assert_eq!(
            NativeFunction::new(mock as NativeCode),
            NativeFunction::new(mock as NativeCode)
        );
        assert!(
            NativeFunction::new(mock as NativeCode)
                != NativeFunction::new(other_mock as NativeCode)
        );
    }

    #[test]
    fn call_native_function() {
        let mut vm = Vm::new(&"");
        assert_eq!(
            vec![] as InstructionSequence,
            NativeFunction::new(mock as NativeCode).call(&mut vm)
        );
    }
}
<commit_msg>Remove warnings in native.rs<commit_after>use ast::{Literal, Pattern};
use std::cmp::Ordering;
use std::fmt;
use std::mem::transmute;
use std::rc::Rc;
use vm::Vm;

#[derive(Clone, Eq, Debug, PartialEq, PartialOrd, Ord)]
pub enum Op {
    Mul,
    Div,
    Add,
    Sub,
}

pub type NativeCode = *const fn(&mut Vm) -> InstructionSequence;

#[derive(Clone)]
pub struct NativeFunction {
    function: NativeCode,
}

impl NativeFunction {
    pub fn new(f: NativeCode) -> Self {
        NativeFunction { function: f }
    }

    pub fn call(&self, vm: &mut Vm) -> InstructionSequence {
        unsafe {
            let func = transmute::<NativeCode, fn(&mut Vm) -> InstructionSequence>(self.function);
            func(vm)
        }
    }
}

impl PartialEq for NativeFunction {
    fn eq(&self, other: &NativeFunction) -> bool {
        self.function as *const _ == other.function as *const _
    }
}

impl Eq for NativeFunction {}

impl Ord for NativeFunction {
    fn cmp(&self, other: &NativeFunction) -> Ordering {
        (self.function as *const usize).cmp(&(other.function as *const usize))
    }
}

impl PartialOrd for NativeFunction {
    fn partial_cmp(&self, other: &NativeFunction) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl fmt::Debug for NativeFunction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "NativeFunction")
    }
}

#[derive(Clone, Eq, Debug, PartialEq, PartialOrd, Ord)]
pub enum Instruction {
    Clear,
    Push(Literal),
    Fetch(String),
    LocalAssign(String),
    Assign(String),
    Call(usize),
    MakeMap(usize),
    Rescue(Rc<Pattern>, Rc<InstructionSequence>),
    IndexAccess,
    IndexAssign,
    Raise,
    BinOp(Op),
    Import,
    Native(NativeFunction),
}

pub type InstructionSequence = Vec<Instruction>;

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

    fn mock(_: &mut Vm) -> InstructionSequence {
        vec![]
    }
    fn other_mock(_: &mut Vm) -> InstructionSequence {
        vec![]
    }

    #[test]
    fn compare_native_functions() {
        assert_eq!(
            NativeFunction::new(mock as NativeCode),
            NativeFunction::new(mock as NativeCode)
        );
        assert!(
            NativeFunction::new(mock as NativeCode)
                != NativeFunction::new(other_mock as NativeCode)
        );
    }

    #[test]
    fn call_native_function() {
        let mut vm = Vm::new(&"");
        assert_eq!(
            vec![] as InstructionSequence,
            NativeFunction::new(mock as NativeCode).call(&mut vm)
        );
    }
}
<|endoftext|>


<commit_before>use crate::{
    channels::Channels, executor::Executor, socket_state::SocketStateHandle, types::ShortUInt,
    Error, Result,
};
use crossbeam_channel::{Receiver, Sender};
use log::trace;
use std::{future::Future, sync::Arc};

pub(crate) struct InternalRPC {
    rpc: Receiver<InternalCommand>,
    handle: InternalRPCHandle,
}

#[derive(Clone)]
pub(crate) struct InternalRPCHandle {
    sender: Sender<InternalCommand>,
    waker: SocketStateHandle,
    executor: Arc<dyn Executor>,
}

impl InternalRPCHandle {
    pub(crate) fn close_channel(&self, channel_id: u16, reply_code: ShortUInt, reply_text: String) {
        self.send(InternalCommand::CloseChannel(
            channel_id, reply_code, reply_text,
        ));
    }

    pub(crate) fn close_connection(
        &self,
        reply_code: ShortUInt,
        reply_text: String,
        class_id: ShortUInt,
        method_id: ShortUInt,
    ) {
        self.send(InternalCommand::CloseConnection(
            reply_code, reply_text, class_id, method_id,
        ));
    }

    pub(crate) fn send_connection_close_ok(&self, error: Error) {
        self.send(InternalCommand::SendConnectionCloseOk(error));
    }

    pub(crate) fn remove_channel(&self, channel_id: u16, error: Error) {
        self.send(InternalCommand::RemoveChannel(channel_id, error));
    }

    pub(crate) fn set_connection_closing(&self) {
        self.send(InternalCommand::SetConnectionClosing);
    }

    pub(crate) fn set_connection_closed(&self, error: Error) {
        self.send(InternalCommand::SetConnectionClosed(error));
    }

    pub(crate) fn set_connection_error(&self, error: Error) {
        self.send(InternalCommand::SetConnectionError(error));
    }

    fn send(&self, command: InternalCommand) {
        trace!("Queuing internal RPC command: {:?}", command);
        self.sender.send(command).expect("internal RPC failed");
        self.waker.wake();
    }

    pub(crate) fn register_internal_future(
        &self,
        f: impl Future<Output = Result<()>> + Send + 'static,
    ) -> Result<()> {
        let internal_rpc = self.clone();
        self.executor.spawn(Box::pin(async move {
            if let Err(err) = f.await {
                internal_rpc.set_connection_error(err);
            }
        }))
    }
}

#[derive(Debug)]
enum InternalCommand {
    CloseChannel(u16, ShortUInt, String),
    CloseConnection(ShortUInt, String, ShortUInt, ShortUInt),
    SendConnectionCloseOk(Error),
    RemoveChannel(u16, Error),
    SetConnectionClosing,
    SetConnectionClosed(Error),
    SetConnectionError(Error),
}

impl InternalRPC {
    pub(crate) fn new(executor: Arc<dyn Executor>, waker: SocketStateHandle) -> Self {
        let (sender, rpc) = crossbeam_channel::unbounded();
        let handle = InternalRPCHandle {
            sender,
            waker,
            executor,
        };
        Self { rpc, handle }
    }

    pub(crate) fn handle(&self) -> InternalRPCHandle {
        self.handle.clone()
    }

    pub(crate) fn poll(&self, channels: &Channels) -> Result<()> {
        while let Ok(command) = self.rpc.try_recv() {
            self.run(command, channels)?;
        }
        Ok(())
    }

    fn run(&self, command: InternalCommand, channels: &Channels) -> Result<()> {
        use InternalCommand::*;

        trace!("Handling internal RPC command: {:?}", command);
        match command {
            CloseChannel(channel_id, reply_code, reply_text) => channels
                .get(channel_id)
                .map(|channel| {
                    self.handle
                        .register_internal_future(channel.close(reply_code, &reply_text))
                })
                .unwrap_or(Ok(())),
            CloseConnection(reply_code, reply_text, class_id, method_id) => channels
                .get(0)
                .map(|channel0| {
                    self.handle
                        .register_internal_future(channel0.connection_close(
                            reply_code,
                            &reply_text,
                            class_id,
                            method_id,
                        ))
                })
                .unwrap_or(Ok(())),
            SendConnectionCloseOk(error) => channels
                .get(0)
                .map(|channel| {
                    self.handle
                        .register_internal_future(channel.connection_close_ok(error))
                })
                .unwrap_or(Ok(())),
            RemoveChannel(channel_id, error) => channels.remove(channel_id, error),
            SetConnectionClosing => {
                channels.set_connection_closing();
                Ok(())
            }
            SetConnectionClosed(error) => channels.set_connection_closed(error),
            SetConnectionError(error) => channels.set_connection_error(error),
        }
    }
}
<commit_msg>InternalRPC: avoid asserting<commit_after>use crate::{
    channels::Channels, executor::Executor, socket_state::SocketStateHandle, types::ShortUInt,
    Error, Result,
};
use crossbeam_channel::{Receiver, Sender};
use log::trace;
use std::{future::Future, sync::Arc};

pub(crate) struct InternalRPC {
    rpc: Receiver<InternalCommand>,
    handle: InternalRPCHandle,
}

#[derive(Clone)]
pub(crate) struct InternalRPCHandle {
    sender: Sender<InternalCommand>,
    waker: SocketStateHandle,
    executor: Arc<dyn Executor>,
}

impl InternalRPCHandle {
    pub(crate) fn close_channel(&self, channel_id: u16, reply_code: ShortUInt, reply_text: String) {
        self.send(InternalCommand::CloseChannel(
            channel_id, reply_code, reply_text,
        ));
    }

    pub(crate) fn close_connection(
        &self,
        reply_code: ShortUInt,
        reply_text: String,
        class_id: ShortUInt,
        method_id: ShortUInt,
    ) {
        self.send(InternalCommand::CloseConnection(
            reply_code, reply_text, class_id, method_id,
        ));
    }

    pub(crate) fn send_connection_close_ok(&self, error: Error) {
        self.send(InternalCommand::SendConnectionCloseOk(error));
    }

    pub(crate) fn remove_channel(&self, channel_id: u16, error: Error) {
        self.send(InternalCommand::RemoveChannel(channel_id, error));
    }

    pub(crate) fn set_connection_closing(&self) {
        self.send(InternalCommand::SetConnectionClosing);
    }

    pub(crate) fn set_connection_closed(&self, error: Error) {
        self.send(InternalCommand::SetConnectionClosed(error));
    }

    pub(crate) fn set_connection_error(&self, error: Error) {
        self.send(InternalCommand::SetConnectionError(error));
    }

    fn send(&self, command: InternalCommand) {
        trace!("Queuing internal RPC command: {:?}", command);
        // The only scenario where this can fail if this is the IoLoop already exited
        let _ = self.sender.send(command);
        self.waker.wake();
    }

    pub(crate) fn register_internal_future(
        &self,
        f: impl Future<Output = Result<()>> + Send + 'static,
    ) -> Result<()> {
        let internal_rpc = self.clone();
        self.executor.spawn(Box::pin(async move {
            if let Err(err) = f.await {
                internal_rpc.set_connection_error(err);
            }
        }))
    }
}

#[derive(Debug)]
enum InternalCommand {
    CloseChannel(u16, ShortUInt, String),
    CloseConnection(ShortUInt, String, ShortUInt, ShortUInt),
    SendConnectionCloseOk(Error),
    RemoveChannel(u16, Error),
    SetConnectionClosing,
    SetConnectionClosed(Error),
    SetConnectionError(Error),
}

impl InternalRPC {
    pub(crate) fn new(executor: Arc<dyn Executor>, waker: SocketStateHandle) -> Self {
        let (sender, rpc) = crossbeam_channel::unbounded();
        let handle = InternalRPCHandle {
            sender,
            waker,
            executor,
        };
        Self { rpc, handle }
    }

    pub(crate) fn handle(&self) -> InternalRPCHandle {
        self.handle.clone()
    }

    pub(crate) fn poll(&self, channels: &Channels) -> Result<()> {
        while let Ok(command) = self.rpc.try_recv() {
            self.run(command, channels)?;
        }
        Ok(())
    }

    fn run(&self, command: InternalCommand, channels: &Channels) -> Result<()> {
        use InternalCommand::*;

        trace!("Handling internal RPC command: {:?}", command);
        match command {
            CloseChannel(channel_id, reply_code, reply_text) => channels
                .get(channel_id)
                .map(|channel| {
                    self.handle
                        .register_internal_future(channel.close(reply_code, &reply_text))
                })
                .unwrap_or(Ok(())),
            CloseConnection(reply_code, reply_text, class_id, method_id) => channels
                .get(0)
                .map(|channel0| {
                    self.handle
                        .register_internal_future(channel0.connection_close(
                            reply_code,
                            &reply_text,
                            class_id,
                            method_id,
                        ))
                })
                .unwrap_or(Ok(())),
            SendConnectionCloseOk(error) => channels
                .get(0)
                .map(|channel| {
                    self.handle
                        .register_internal_future(channel.connection_close_ok(error))
                })
                .unwrap_or(Ok(())),
            RemoveChannel(channel_id, error) => channels.remove(channel_id, error),
            SetConnectionClosing => {
                channels.set_connection_closing();
                Ok(())
            }
            SetConnectionClosed(error) => channels.set_connection_closed(error),
            SetConnectionError(error) => channels.set_connection_error(error),
        }
    }
}
<|endoftext|>


<commit_before>//! This module contains the implementation of an interval heap data structure.

use std::mem;
use std::vec;

// Interval Heap:
// --------------
// (1) each node (except possibly the last leaf) contains two values
//     where the first one is less than or equal to the second one
// (2) each node represents a closed interval
// (3) a child node's interval is completely contained in the parent node's
//     interval

// item indices...
//
//          (0 1)
//         /     \
//    (2 3)       (4 5)
//    /   \       /    \
//  (6 7)(8 9)(10 11)(12 13)
//  ........................

// v[x] for x in [0,len-1) is considered a valid interval heap.
// The last item in v is to be added.
fn inteval_heap_push<T: Ord>(v: &mut [T]) {
    debug_assert!(v.len() > 0);
    let mut node_r = v.len() - 1;
    let mut node_l = node_r & !1u;
    if v[node_l] > v[node_r] { v.swap(node_l, node_r); }
    while node_l > 0 {
        let parent_l = (node_l / 2 - 1) & !1u;
        let parent_r = parent_l + 1;
        if v[node_l] < v[parent_l] {
            v.swap(parent_l, node_l);
        } else if v[parent_r] < v[node_r] {
            v.swap(parent_r, node_r);
        } else {
            return; // nothing to do anymore
        }
        debug_assert!(!(v[node_r] < v[node_l]));
        node_l = parent_l;
        node_r = parent_r;
    }
}

// pushes item v[index] down the tree as needed
// to restore interval heap properties
fn down_min<T: Ord>(v: &mut [T], mut index: uint) {
    debug_assert!(index & 1 == 0);
    loop {
        let c1 = index * 2 + 2;
        let c2 = index * 2 + 4;
        if v.len() <= c1 { return; }
        // which path to go down in the tree?
        let ch = if v.len() <= c2 {
                     c1 // c1 is the only child
                 } else {
                     if v[c1] < v[c2] { c1 } else { c2 }
                 };
        if v[ch] < v[index] {
            v.swap(ch, index);
            index = ch;
            let right = index + 1;
            if right < v.len() {
                if v[index] > v[right] { v.swap(index, right); }
            }
        } else {
            break;
        }
    }
}

// pushes item v[index] down the tree as needed
// to restore interval heap properties
fn down_max<T: Ord>(v: &mut [T], mut index: uint) {
    debug_assert!(index & 1 == 1);
    loop {
        let c1 = index * 2 + 1;
        let c2 = index * 2 + 3;
        if v.len() <= c1 { return; }
        // which path to go down in the tree?
        let ch = if v.len() <= c2 {
                     c1 // c1 is the only child
                 } else {
                     if v[c1] > v[c2] { c1 } else { c2 }
                 };
        if v[ch] > v[index] {
            v.swap(ch, index);
            index = ch;
            let left = index - 1;
            if v[left] > v[index] { v.swap(left, index); }
        } else {
            break;
        }
    }
}

// replaces and element and propagates the new one down the tree
fn replace_and_down<T: Ord>(v: &mut [T], index: uint, x: T) -> T {
    let res = mem::replace(&mut v[index], x);
    if index & 1 == 0 { down_min(v, index); }
    else { down_max(v, index); }
    res
}

/// An `IntervalHeap` is an implementation of a double-ended priority queue.
/// As such, it supports the following operations: `push`, `get_min`,
/// `get_max`, `pop_min`, `pop_max` where insertion takes amortized O(log n)
/// time, removal takes O(log n) time and accessing minimum and maximum can
/// be done in constant time. Also, other convenient functions are provided
/// that handle conversion from and into vectors and allow iteration etc.
#[deriving(Clone)]
pub struct IntervalHeap<T> {
    data: Vec<T>
}

pub type MoveItems<T> = vec::MoveItems<T>;

impl<T> IntervalHeap<T> {
    /// creates empty interval heap
    pub fn new() -> IntervalHeap<T> {
        IntervalHeap { data: Vec::new() }
    }
    /// creates empty interval heap with a user-defined initial capacity
    /// which causes insertions not to reallocate memory if the capacity
    /// is sufficient to hold the new items.
    pub fn with_capacity(c: uint) -> IntervalHeap<T> {
        IntervalHeap { data: Vec::with_capacity(c) }
    }
    /// returns true if the queue contains no items
    pub fn is_empty(&self) -> bool {
        self.data.is_empty()
    }
    /// drops all items from the queue
    pub fn clear(&mut self) {
        self.data.clear();
    }
    /// converts the interval heap into a vector (constant time complexity)
    pub fn into_vec(self) -> Vec<T> {
        self.data
    }
    /// converts the interval heap into an iterator
    pub fn into_iter(self) -> MoveItems<T> {
        self.data.into_iter()
    }
    /// returns the number of items in the interval heap
    pub fn len(&self) -> uint {
        self.data.len()
    }
    /// returns the number of items the interval heap could hold
    /// without any memory reallocation
    pub fn capacity(&self) -> uint {
        self.data.capacity()
    }
    /// reserves capacity for at least `additional` more elements to be
    /// inserted in the `IntervalHeap`. The collection may reserve more
    /// space to avoid frequent reallocations.
    pub fn reserve(&mut self, additional: uint) {
        self.data.reserve(additional);
    }
    /// discards as much additional capacity as possible.
    pub fn shrink_to_fit(&mut self) {
        self.data.shrink_to_fit()
    }
    /// provides read-access to all the items.
    pub fn as_slice(&self) -> &[T] {
        self.data.as_slice()
    }
    /// returns a reference to the minimal item or None (if empty)
    pub fn get_min<'a>(&'a self) -> Option<&'a T> {
        match self.data.len() {
            0 => None,
            _ => Some(&self.data[0])
        }
    }
    /// returns a reference to the maximum item or None (if empty)
    pub fn get_max<'a>(&'a self) -> Option<&'a T> {
        match self.data.len() {
            0 => None,
            1 => Some(&self.data[0]),
            _ => Some(&self.data[1])
        }
    }
    /// returns a reference to the minimal and maximum item or None (if empty)
    pub fn get_min_max<'a>(&'a self) -> Option<(&'a T, &'a T)> {
        match self.data.len() {
            0 => None,
            1 => Some((&self.data[0],&self.data[0])),
            _ => Some((&self.data[0],&self.data[1]))
        }
    }
}

impl<T: Ord> IntervalHeap<T> {
    /// converts a vector into an interval heap in-place. No memory
    /// allocation will be done. The time complexity is O(n log n) and
    /// O(n) in case the vector already represents an interval heap.
    pub fn from_vec(mut v: Vec<T>) -> IntervalHeap<T> {
        for to in range(2, v.len()) {
            inteval_heap_push(v.slice_to_mut(to));
        }
        IntervalHeap { data: v }
    }
    /// inserts a new item into the queue, takes amortized
    /// logarithmic time in the size of the heap
    pub fn push(&mut self, x: T) {
        self.data.push(x);
        inteval_heap_push(self.data.as_mut_slice());
    }
    /// pushes a new element into the interval heap and immediately
    /// pops the minimum (possibly returning the new element).
    /// This is expected to be a little more efficient than separate
    /// calls to `push` and `pop_min`. So, no matter
    /// what, the size of the heap will not change.
    pub fn push_and_pop_min(&mut self, x: T) -> T {
        match self.data.len() {
            0 => x,
            _ => if self.data[0] >= x { x }
                 else { replace_and_down(self.data.as_mut_slice(), 0, x) }
        }
    }
    /// pushes a new element into the interval heap and immediately
    /// pops the maximum (possibly returning the new element).
    /// This is expected to be a little more efficient than separate
    /// calls to `push` and `pop_max`. So, no matter
    /// what, the size of the heap will not change.
    pub fn push_and_pop_max(&mut self, x: T) -> T {
        match self.data.len() {
            0 => x,
            l => {
                let index = if l==1 { 0u } else { 1u };
                replace_and_down(self.data.as_mut_slice(), index, x)
            }
        }
    }
    /// replaces the minimum item with the given `x`. If the heap is
    /// empty, this function will return `Err(x)`. If the heap is
    /// not empty, the function returns `Ok(old_min)`. So, no matter
    /// what, the size of the heap will not change.
    pub fn replace_min(&mut self, x: T) -> Result<T,T> {
        match self.data.len() {
            0 => Err(x),
            _ => Ok(replace_and_down(self.data.as_mut_slice(), 0, x))
        }
    }
    /// replaces the maximum item with the given `x`. If the heap is
    /// empty, this function will return `Err(x)`. If the heap is
    /// not empty, the function returns `Ok(old_min)`. So, no matter
    /// what, the size of the heap will not change.
    pub fn replace_max(&mut self, x: T) -> Result<T,T> {
        match self.data.len() {
            0 => Err(x),
            1 => Ok(mem::replace(&mut self.data[0], x)),
            _ => Ok(replace_and_down(self.data.as_mut_slice(), 1, x))
        }
    }
    /// removes the minimum item and returns it (or None if empty),
    /// takes logarithmic time in the size of the heap
    pub fn pop_min(&mut self) -> Option<T> {
        match self.data.len() {
            0 => None,
            1...2 => self.data.swap_remove(0),
            _ => { // length 3 or higher
                let res = self.data.swap_remove(0);
                down_min(self.data.as_mut_slice(), 0);
                res
            }
        }
    }
    /// removes the maximum item and returns it (or None if empty),
    /// takes logarithmic time in the size of the heap
    pub fn pop_max(&mut self) -> Option<T> {
        match self.data.len() {
            0 => None,
            1...2 => self.data.pop(),
            _ => { // length 3 or higher
                let res = self.data.swap_remove(1);
                down_max(self.data.as_mut_slice(), 1);
                res
            }
        }
    }
}

impl<T> Deref<[T]> for IntervalHeap<T> {
    /// allows all the immutable slice methods on the interval heap
    fn deref(&self) -> &[T] {
        self.as_slice()
    }
}

impl<T: Ord> FromIterator<T> for IntervalHeap<T> {
    /// creates an interval heap with all the items from an iterator
    fn from_iter<Iter: Iterator<T>>(mut iter: Iter) -> IntervalHeap<T> {
        let vec: Vec<T> = iter.collect();
        IntervalHeap::from_vec(vec)
    }
}

impl<T: Ord> Extend<T> for IntervalHeap<T> {
    /// extends the interval heap by a new chunk of items given by
    /// an iterator.
    fn extend<Iter: Iterator<T>>(&mut self, mut iter: Iter) {
        let (lower, _) = iter.size_hint();
        self.reserve(lower);
        for elem in iter {
            self.push(elem);
        }
    }
}

#[cfg(test)]
mod ih_test {
    use std::rand::{task_rng, Rng};
    use super::IntervalHeap;

    // TODO: more testing (push_and_pop_xxx, replace_xxx)

    fn is_interval_heap<T: Ord>(x: &[T]) -> bool {
        if x.len() < 2 { return true; }
        if x[1] < x[0] { return false; }
        let mut ofs = 2;
        while ofs < x.len() {
            let ofz = ofs + (ofs + 1 < x.len()) as uint;
            if x[ofz] < x[ofs] { return false; }
            let parent = (ofs / 2 - 1) & !1u;
            if x[ofs] < x[parent] { return false; }
            if x[parent+1] < x[ofz] { return false; }
            ofs += 2;
        }
        true
    }

    #[test]
    fn random_check_push() {
        let mut rng = task_rng();
        for _ in range(0, 1000u) {
            let mut ih: IntervalHeap<u32> = IntervalHeap::new();
            for _ in range(0, 100u) {
                ih.push(rng.next_u32());
                assert!(is_interval_heap(ih.as_slice()));
            }
        }
    }

    #[test]
    fn random_check_pop_min() {
        let mut rng = task_rng();
        for _ in range(0, 1000u) {
            let mut ih: IntervalHeap<u32> = IntervalHeap::new();
            for _ in range(0, 100u) {
                ih.push(rng.next_u32());
            }
            let mut tmpx: Option<u32> = None;
            loop {
                let tmpy = ih.pop_min();
                assert!(is_interval_heap(ih.as_slice()));
                match (tmpx, tmpy) {
                    (_, None) => break,
                    (Some(x), Some(y)) => assert!(x <= y),
                    _ => ()
                }
                tmpx = tmpy;
            }
        }
    }

    #[test]
    fn random_check_pop_max() {
        let mut rng = task_rng();
        for _ in range(0, 1000u) {
            let mut ih: IntervalHeap<u32> = IntervalHeap::new();
            for _ in range(0, 100u) {
                ih.push(rng.next_u32());
            }
            let mut tmpx: Option<u32> = None;
            loop {
                let tmpy = ih.pop_max();
                assert!(is_interval_heap(ih.as_slice()));
                match (tmpx, tmpy) {
                    (_, None) => break,
                    (Some(x), Some(y)) => assert!(x >= y),
                    _ => ()
                }
                tmpx = tmpy;
            }
        }
    }

} // mod test

<commit_msg>intervalheap: more docs, style, add into_sorted_vec and test<commit_after>//! A double-ended priority queue implemented with an interval heap.

use std::slice;
use std::default::Default;

// An interval heap is a binary tree structure with the following properties:
//
// (1) Each node (except possibly the last leaf) contains two values
//     where the first one is less than or equal to the second one.
// (2) Each node represents a closed interval.
// (3) A child node's interval is completely contained in the parent node's
//     interval.
//
// This implies that the min and max elements are always in the root node.
//
// This interval heap implementation stores its nodes in a linear array
// using a Vec. Here's an example of the layout of a tree with 13 items
// (7 nodes) where the numbers represent the *offsets* in the array:
//
//          (0 1)
//         /     \
//    (2 3)       (4 5)
//    /   \       /    \
//  (6 7)(8 9)(10 11)(12 --)
//
// Even indices are used for the "left" element of a node while odd indices
// are used for the "right" element of a node. Note: the last node may not
// have a "right" element.

// FIXME: There may be a better algorithm for turning a vector into an
// interval heap. Right now, this takes O(n log n) time, I think.

fn is_root(x: uint) -> bool { x < 2 }

/// Set LSB to zero for the "left" item index of a node.
fn left(x: uint) -> uint { x & !1u }

/// Returns index of "left" item of parent node.
fn parent_left(x: uint) -> uint {
    debug_assert!(!is_root(x));
    left((x - 2) / 2)
}

/// The first `v.len() - 1` elements are considered a valid interval heap
/// and the last element is to be inserted.
fn inteval_heap_push<T: Ord>(v: &mut [T]) {
    debug_assert!(v.len() > 0);
    // Start with the last new/modified node and work our way to
    // the root if necessary...
    let mut node_max = v.len() - 1;
    let mut node_min = left(node_max);
    // The reason for using two variables instead of one is to
    // get around the special case of the last node only containing
    // one element (node_min == node_max).
    if v[node_min] > v[node_max] { v.swap(node_min, node_max); }
    while !is_root(node_min) {
        let par_min = parent_left(node_min);
        let par_max = par_min + 1;
        if v[node_min] < v[par_min] {
            v.swap(par_min, node_min);
        } else if v[par_max] < v[node_max] {
            v.swap(par_max, node_max);
        } else {
            return; // nothing to do anymore
        }
        debug_assert!(v[node_min] <= v[node_max]);
        node_min = par_min;
        node_max = par_max;
    }
}

/// The min element in the root node of an otherwise valid interval heap
/// has been been replaced with some other value without violating rule (1)
/// for the root node. This function restores the interval heap properties.
fn update_min<T: Ord>(v: &mut [T]) {
    // Starting at the root, we go down the tree...
    debug_assert!(v[0] <= v[1]);
    let mut left = 0;
    loop {
        let c1 = left * 2 + 2; // index of 1st child's left element
        let c2 = left * 2 + 4; // index of 2nd child's left element
        if v.len() <= c1 { return; } // No children. We're done.
        // Pick child with lowest min
        let ch = if v.len() <= c2 || v[c1] < v[c2] { c1 }
                 else { c2 };
        if v[ch] < v[left] {
            v.swap(ch, left);
            left = ch;
            let right = left + 1;
            if right < v.len() {
                if v[left] > v[right] { v.swap(left, right); }
            }
        } else {
            break;
        }
    }
}

/// The max element in the root node of an otherwise valid interval heap
/// has been been replaced with some other value without violating rule (1)
/// for the root node. This function restores the interval heap properties.
fn update_max<T: Ord>(v: &mut [T]) {
    debug_assert!(v[0] <= v[1]);
    // Starting at the root, we go down the tree...
    let mut right = 1;
    loop {
        let c1 = right * 2 + 1; // index of 1st child's right element
        let c2 = right * 2 + 3; // index of 2nd child's right element
        if v.len() <= c1 { return; } // No children. We're done.
        // Pick child with greatest max
        let ch = if v.len() <= c2 || v[c1] > v[c2] { c1 }
                 else { c2 };
        if v[ch] > v[right] {
            v.swap(ch, right);
            right = ch;
            let left = right - 1; // always exists
            if v[left] > v[right] { v.swap(left, right); }
        } else {
            break;
        }
    }
}

/// An `IntervalHeap` is an implementation of a double-ended priority queue.
/// As such, it supports the following operations: `push`, `get_min`,
/// `get_max`, `pop_min`, `pop_max` where insertion takes amortized O(log n)
/// time, removal takes O(log n) time and accessing minimum and maximum can
/// be done in constant time. Also, other convenient functions are provided
/// that handle conversion from and into vectors and allow iteration etc.
#[deriving(Clone)]
pub struct IntervalHeap<T> {
    data: Vec<T>
}

impl<T: Ord> Default for IntervalHeap<T> {
    /// Creates an empty `IntervalHeap`.
    #[inline]
    fn default() -> IntervalHeap<T> { IntervalHeap::new() }
}

/// `IntervalHeap` iterator.
pub type Items<'a, T> = slice::Items<'a, T>;

impl<T: Ord> IntervalHeap<T> {
    /// Creates an empty `IntervalHeap`.
    pub fn new() -> IntervalHeap<T> {
        IntervalHeap { data: Vec::new() }
    }

    /// Creates an empty `IntervalHeap` with a specific capacity. This
    /// preallocates enough memory for capacity elements, so that the
    /// `IntervalHeap` does not have to be reallocated until it contains at
    /// least that many values.
    pub fn with_capacity(c: uint) -> IntervalHeap<T> {
        IntervalHeap { data: Vec::with_capacity(c) }
    }

    /// Creates an `IntervalHeap` from a vector.
    pub fn from_vec(mut v: Vec<T>) -> IntervalHeap<T> {
        for to in range(2, v.len()) {
            inteval_heap_push(v.slice_to_mut(to));
        }
        IntervalHeap { data: v }
    }

    /// An iterator visiting all values in underlying vector,
    /// in arbitrary order.
    pub fn iter(&self) -> Items<T> {
        self.data.iter()
    }

    /// Returns a reference to the smallest item or None (if empty).
    pub fn get_min(&self) -> Option<&T> {
        match self.data.len() {
            0 => None,
            _ => Some(&self.data[0])
        }
    }

    /// Returns a reference to the greatest item or None (if empty).
    pub fn get_max(&self) -> Option<&T> {
        match self.data.len() {
            0 => None,
            1 => Some(&self.data[0]),
            _ => Some(&self.data[1])
        }
    }

    /// Returns references to the smallest and greatest item or None (if empty).
    pub fn get_min_max(&self) -> Option<(&T, &T)> {
        match self.data.len() {
            0 => None,
            1 => Some((&self.data[0],&self.data[0])),
            _ => Some((&self.data[0],&self.data[1]))
        }
    }

    /// Returns the number of items the interval heap could hold
    /// without reallocation.
    pub fn capacity(&self) -> uint {
        self.data.capacity()
    }

    /// Reserves the minimum capacity for exactly `additional` more elements
    /// to be inserted in the given `IntervalHeap`. Does nothing if the capacity
    /// is already sufficient.
    ///
    /// Note that the allocator may give the collection more space than it
    /// requests. Therefore capacity can not be relied upon to be precisely
    /// minimal. Prefer `reserve` if future insertions are expected.
    pub fn reserve_exact(&mut self, additional: uint) {
        self.data.reserve_exact(additional);
    }

    /// Reserves capacity for at least `additional` more elements to be inserted
    /// in the `IntervalHeap`. The collection may reserve more space to avoid
    /// frequent reallocations.
    pub fn reserve(&mut self, additional: uint) {
        self.data.reserve(additional);
    }

    /// Discards as much additional capacity as possible.
    pub fn shrink_to_fit(&mut self) {
        self.data.shrink_to_fit()
    }

    /// Removes the smallest item and returns it, or None if is empty.
    pub fn pop_min(&mut self) -> Option<T> {
        match self.data.len() {
            0 => None,
            1...2 => self.data.swap_remove(0),
            _ => {
                let res = self.data.swap_remove(0);
                update_min(self.data.as_mut_slice());
                res
            }
        }
    }

    /// Removes the greatest item and returns it, or None if is empty.
    pub fn pop_max(&mut self) -> Option<T> {
        match self.data.len() {
            0...2 => self.data.pop(),
            _ => {
                let res = self.data.swap_remove(1);
                update_max(self.data.as_mut_slice());
                res
            }
        }
    }

    /// Pushes an item onto the queue.
    pub fn push(&mut self, x: T) {
        self.data.push(x);
        inteval_heap_push(self.data.as_mut_slice());
    }

    /// Consumes the `IntervalHeap` and returns the underlying vector
    /// in arbitrary order.
    pub fn into_vec(self) -> Vec<T> { self.data }

    /// Consumes the `IntervalHeap` and returns a vector in sorted
    /// (ascending) order.
    pub fn into_sorted_vec(self) -> Vec<T> {
        let mut vec = self.data;
        for hsize in range(2, vec.len()).rev() {
            vec.swap(1, hsize);
            update_max(vec.slice_to_mut(hsize));
        }
        vec
    }

    /// Returns the number of items in the interval heap
    pub fn len(&self) -> uint {
        self.data.len()
    }

    /// Returns true if the queue contains no items.
    pub fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    /// Drops all items from the queue.
    pub fn clear(&mut self) {
        self.data.clear();
    }
}

impl<T: Ord> FromIterator<T> for IntervalHeap<T> {
    /// Creates an interval heap with all the items from an iterator
    fn from_iter<Iter: Iterator<T>>(mut iter: Iter) -> IntervalHeap<T> {
        let vec: Vec<T> = iter.collect();
        IntervalHeap::from_vec(vec)
    }
}

impl<T: Ord> Extend<T> for IntervalHeap<T> {
    /// Extends the interval heap by a new chunk of items given by
    /// an iterator.
    fn extend<Iter: Iterator<T>>(&mut self, mut iter: Iter) {
        let (lower, _) = iter.size_hint();
        self.reserve(lower);
        for elem in iter {
            self.push(elem);
        }
    }
}

#[cfg(test)]
pub fn as_slice<T>(x: &IntervalHeap<T>) -> &[T] {
    x.data.as_slice()
}

#[cfg(test)]
mod test {
    use std::rand::{ task_rng, Rng };
    use super::{ IntervalHeap, as_slice };

    fn is_interval_heap<T: Ord>(x: &[T]) -> bool {
        if x.len() < 2 { return true; }
        if x[1] < x[0] { return false; }
        let mut ofs = 2;
        while ofs < x.len() {
            let ofz = ofs + (ofs + 1 < x.len()) as uint;
            if x[ofz] < x[ofs] { return false; }
            let parent = (ofs / 2 - 1) & !1u;
            if x[ofs] < x[parent] { return false; }
            if x[parent+1] < x[ofz] { return false; }
            ofs += 2;
        }
        true
    }

    #[test]
    fn fuzz_push_into_sorted_vec() {
        let mut rng = task_rng();
        let mut tmp = Vec::with_capacity(100);
        for _ in range(0, 100u) {
            tmp.clear();
            let mut ih: IntervalHeap<u32> = IntervalHeap::from_vec(tmp);
            for _ in range(0, 100u) {
                ih.push(rng.next_u32());
                assert!(is_interval_heap(as_slice(&ih)));
            }
            tmp = ih.into_sorted_vec();
            for pair in tmp.windows(2) {
                assert!(pair[0] <= pair[1]);
            }
        }
    }

    #[test]
    fn fuzz_pop_min() {
        let mut rng = task_rng();
        let mut tmp = Vec::with_capacity(100);
        for _ in range(0, 100u) {
            tmp.clear();
            let mut ih: IntervalHeap<u32> = IntervalHeap::from_vec(tmp);
            for _ in range(0, 100u) {
                ih.push(rng.next_u32());
            }
            let mut tmpx: Option<u32> = None;
            loop {
                let tmpy = ih.pop_min();
                assert!(is_interval_heap(as_slice(&ih)));
                match (tmpx, tmpy) {
                    (_, None) => break,
                    (Some(x), Some(y)) => assert!(x <= y),
                    _ => ()
                }
                tmpx = tmpy;
            }
            tmp = ih.into_vec();
        }
    }

    #[test]
    fn fuzz_pop_max() {
        let mut rng = task_rng();
        let mut tmp = Vec::with_capacity(100);
        for _ in range(0, 100u) {
            tmp.clear();
            let mut ih: IntervalHeap<u32> = IntervalHeap::from_vec(tmp);
            for _ in range(0, 100u) {
                ih.push(rng.next_u32());
            }
            let mut tmpx: Option<u32> = None;
            loop {
                let tmpy = ih.pop_max();
                assert!(is_interval_heap(as_slice(&ih)));
                match (tmpx, tmpy) {
                    (_, None) => break,
                    (Some(x), Some(y)) => assert!(x >= y),
                    _ => ()
                }
                tmpx = tmpy;
            }
            tmp = ih.into_vec();
        }
    }

} // mod test

<|endoftext|>


<commit_before>//! A simple first program in rust, actually I plan to do something even
//! useful. Trying to find all my audiobooks on many machines, identify them,
//! find duplicates (later trying to solve the problem, also including their permissions,
//! different names, but same albums, etc, get all stats about it).
//! It acts as a wrapper around adbflib, which holds major parts of the implemention.
//!
//! For debugging, use e.g.
//!   ADBF_LOG_LVL=file RUST_BACKTRACE=full RUST_LOG=adbfbinlib::webui=trace
//!
//!               ADBF_LOG_LVL=file   : is the method
//!               RUST_BACKTRACE=full : is Rust's trace level
//!  RUST_LOG=adbfbinlib::webui=trace : is program's inner debugging mod
//!

mod command_line;

use adbfbinlib::{
    common::{logit, paths::SearchPath},
    ctrl::{Ctrl, UiUpdateMsg},
    data::{
        collection::Collection,
        ipc::{IFCollectionOutputData, IPC},
    },
    net::subs::key_keeper,
    shared,
};
use async_std::task;
use crossbeam::{channel::unbounded, sync::WaitGroup};
use ctrlc;
use exitcode;
use log::{error, info, trace};
use num_cpus;
use std::{
    cmp, env, io, process,
    sync::{Arc as SArc, Mutex as SMutex},
};

/// The main application which is central part of communicating with
/// the adbflib, which is closely connected.
fn main() -> io::Result<()> {
    // get start values from the input parser!!!
    let (ui_paths, has_tui, has_webui, has_net, keep_alive, open_browser, web_port, has_ui) =
        command_line::get_start_values();

    // read into paths
    let cleaned_paths = SearchPath::new(&ui_paths);
    if cleaned_paths.len() != ui_paths.len() && !has_tui && !has_webui && !open_browser {
        println!("Some paths/folders intersect and will not be used!");
    }

    // only use the arc
    let search_path = SArc::new(SMutex::new(cleaned_paths));
    let search_path_ui = search_path.clone();

    // define collection thread pool
    let ctrlc_thread = 1;
    let assumed_number_of_threads_used = if has_webui { 1 } else { 0 }
        + if has_tui { 1 } else { 0 }
        + if has_net { 1 } else { 0 }
        + ctrlc_thread;
    let nr_cpus = num_cpus::get();
    let nr_threads_for_collection = if assumed_number_of_threads_used >= nr_cpus {
        1
    } else {
        nr_cpus - assumed_number_of_threads_used
    };
    rayon::ThreadPoolBuilder::new()
        .thread_name(|nr| format!("col_{}", nr))
        .num_threads(nr_threads_for_collection)
        .build_global()
        .unwrap();

    // for synced start of different threads
    let wait_collector = WaitGroup::new();
    let wait_ui = wait_collector.clone();
    let wait_net = wait_collector.clone();

    //
    // prepare the message system
    //
    let (tx, rx) = unbounded::<UiUpdateMsg>();

    // these will be taken directly
    let tx_net = tx.clone();

    // ui message from here (collection)
    let tx_col = tx.clone();

    // for now this will stay wrapped
    let tx_from_collector_to_ui = SArc::new(SMutex::new(tx.clone()));

    // start the logging
    logit::Logit::init(logit::read_env_level(
        &env::var("ADBF_LOG").unwrap_or("".into()),
    ));

    // all optional components are wrapped into threads
    // 1 - UI         ui_thread   (optional)
    // 2 - Net        net_thread  (optional)
    // 3 - Collector  no thread yet (uses multiple rayon worker threads)
    let ui_thread = std::thread::Builder::new()
        .name("ui".into())
        .spawn(move || {
            if has_ui {
                Ctrl::run(
                    key_keeper::get_p2p_server_id(),
                    search_path_ui,
                    rx,
                    has_net,
                    wait_ui,
                    has_webui,
                    has_tui,
                    open_browser,
                    web_port,
                )
            } else {
                info!("no ui was created!");
                drop(wait_ui);
                Ok::<(), std::io::Error>(())
            }
        })?;

    // create a crossbeam channel for massive data exchange
    // with data I called IPC ...
    // in contrast to normal channels crossbeam channels are
    // n:m, so senders can be cloned as well!
    let (ipc_send, ipc_receive) = unbounded::<IPC>();

    // 2 - Net Future
    let net_thread = std::thread::Builder::new()
        .name("net".into())
        .spawn(move || {
            if has_net {
                let sender = Some(tx_net);
                task::block_on(
                    async move { shared::net_search(wait_net, sender, ipc_receive).await },
                )
                .map_err(|error| {
                    std::io::Error::new(
                        std::io::ErrorKind::Other,
                        format!("network error: {}", error),
                    )
                })
            } else {
                info!("no net!");
                drop(wait_net);
                Ok::<(), std::io::Error>(())
            }
        })?;

    // CTRL-C exit handler (is wrapped inside a thread)
    ctrlc::set_handler(move || {
        println!("\n'{}' was manually exited!!!", env!("CARGO_PKG_NAME"));
        process::exit(exitcode::SOFTWARE);
    })
    .map_err(|error| {
        std::io::Error::new(
            std::io::ErrorKind::Other,
            format!(
                "{} terminate signal invokation doesn't work!({:?})",
                env!("CARGO_PKG_NAME"),
                error
            ),
        )
    })?;

    // finished ipc sender reserved before collector takes action
    let ipc_send_finished = ipc_send.clone();

    // the collector
    // but yet this simple bracket to enclose this a little
    {
        trace!("syncing with 2 other threads");
        wait_collector.wait();
        trace!("sync with net and ui done ... collector can start");

        let synced_to_ui_messages = tx_from_collector_to_ui.clone();

        // set up data
        let collection_protected = SArc::new(SMutex::new(Collection::new()));

        // search parallelly
        let output_data = shared::collection_search(
            collection_protected.clone(),
            search_path,
            synced_to_ui_messages,
            has_ui,
        );

        info!("collector finished!!");
        if has_ui || has_net {
            // send own peer and others that are finished
            let memory_used = collection_protected
                .lock()
                .and_then(|collection| Ok(collection.memory()))
                .unwrap_or_else(|_| {
                    error!("locking collection didn't work here!");
                    0
                });

            let mut collection_output = IFCollectionOutputData::from(&output_data);
            // to have not 0 as data size minimum
            collection_output.size_of_data_in_kb = cmp::max(1, (memory_used / 1000) as usize);

            // to others via IPC
            if has_net {
                ipc_send_finished
                    .send(IPC::DoneSearching(collection_output.clone()))
                    .unwrap_or_else(|_| {
                        error!("net has to be up and receiving this send!");
                    });
            }
            // to myself (ui) via UiUpdateMsg
            if has_ui {
                tx_col
                    .send(UiUpdateMsg::PeerSearchFinished(
                        key_keeper::get_p2p_server_id(),
                        collection_output,
                    ))
                    .unwrap_or_else(|e| error!("use one: {}", e));
            }
        }
        if !has_ui {
            collection_protected
                .lock()
                .and_then(|locked_collection| {
                    Ok(locked_collection
                        .print_stats(&key_keeper::get_p2p_server_id(), nr_threads_for_collection))
                })
                .unwrap_or(())
        }
    }

    // look for keeping alive argument if that was chosen
    if keep_alive {
        ui_thread
            .join()
            .unwrap_or_else(|_| {
                // it doesn't matter because we will terminate anyway
                error!("this should be result of ui thread!!");
                Ok(())
            })
            .unwrap();
        if has_ui {
            info!("Stopped ui thread");
        }
        // net thread
        if has_ui {
            // if had a ui , net_thread will stop also after ui quit
            drop(net_thread);
        } else {
            // if didn't have ui, net_thread will continue running
            println!(
                "Search is finished, but net thread is kept running!\nTo stop send break command (ctrl-c)!"
            );
            net_thread
                .join()
                .unwrap_or_else(|_| {
                    // it doesn't matter because we will terminate anyway
                    error!("is this normal when joining net thread???");
                    Ok(())
                })
                .unwrap();
            info!("Stopped net thread");
        }
    } else {
        drop(net_thread);
        drop(ui_thread);
    }
    Ok(())
}
<commit_msg>[refactor] clarify again how to debug<commit_after>//! A simple first program in rust, actually I plan to do something even
//! useful. Trying to find all my audiobooks on many machines, identify them,
//! find duplicates (later trying to solve the problem, also including their permissions,
//! different names, but same albums, etc, get all stats about it).
//! It acts as a wrapper around adbflib, which holds major parts of the implemention.
//!
//! For debugging, use e.g. as env in front of binary
//!   ADBF_LOG_LVL=file RUST_BACKTRACE=full RUST_LOG=adbfbinlib::webui=trace ./audiobookfinder ...
//!
//!               ADBF_LOG_LVL=file   : is the method
//!               RUST_BACKTRACE=full : is Rust's trace level
//!  RUST_LOG=adbfbinlib::webui=trace : is program's inner debugging mod
//!

mod command_line;

use adbfbinlib::{
    common::{logit, paths::SearchPath},
    ctrl::{Ctrl, UiUpdateMsg},
    data::{
        collection::Collection,
        ipc::{IFCollectionOutputData, IPC},
    },
    net::subs::key_keeper,
    shared,
};
use async_std::task;
use crossbeam::{channel::unbounded, sync::WaitGroup};
use ctrlc;
use exitcode;
use log::{error, info, trace};
use num_cpus;
use std::{
    cmp, env, io, process,
    sync::{Arc as SArc, Mutex as SMutex},
};

/// The main application which is central part of communicating with
/// the adbflib, which is closely connected.
fn main() -> io::Result<()> {
    // get start values from the input parser!!!
    let (ui_paths, has_tui, has_webui, has_net, keep_alive, open_browser, web_port, has_ui) =
        command_line::get_start_values();

    // read into paths
    let cleaned_paths = SearchPath::new(&ui_paths);
    if cleaned_paths.len() != ui_paths.len() && !has_tui && !has_webui && !open_browser {
        println!("Some paths/folders intersect and will not be used!");
    }

    // only use the arc
    let search_path = SArc::new(SMutex::new(cleaned_paths));
    let search_path_ui = search_path.clone();

    // define collection thread pool
    let ctrlc_thread = 1;
    let assumed_number_of_threads_used = if has_webui { 1 } else { 0 }
        + if has_tui { 1 } else { 0 }
        + if has_net { 1 } else { 0 }
        + ctrlc_thread;
    let nr_cpus = num_cpus::get();
    let nr_threads_for_collection = if assumed_number_of_threads_used >= nr_cpus {
        1
    } else {
        nr_cpus - assumed_number_of_threads_used
    };
    rayon::ThreadPoolBuilder::new()
        .thread_name(|nr| format!("col_{}", nr))
        .num_threads(nr_threads_for_collection)
        .build_global()
        .unwrap();

    // for synced start of different threads
    let wait_collector = WaitGroup::new();
    let wait_ui = wait_collector.clone();
    let wait_net = wait_collector.clone();

    //
    // prepare the message system
    //
    let (tx, rx) = unbounded::<UiUpdateMsg>();

    // these will be taken directly
    let tx_net = tx.clone();

    // ui message from here (collection)
    let tx_col = tx.clone();

    // for now this will stay wrapped
    let tx_from_collector_to_ui = SArc::new(SMutex::new(tx.clone()));

    // start the logging
    logit::Logit::init(logit::read_env_level(
        &env::var("ADBF_LOG").unwrap_or("".into()),
    ));

    // all optional components are wrapped into threads
    // 1 - UI         ui_thread   (optional)
    // 2 - Net        net_thread  (optional)
    // 3 - Collector  no thread yet (uses multiple rayon worker threads)
    let ui_thread = std::thread::Builder::new()
        .name("ui".into())
        .spawn(move || {
            if has_ui {
                Ctrl::run(
                    key_keeper::get_p2p_server_id(),
                    search_path_ui,
                    rx,
                    has_net,
                    wait_ui,
                    has_webui,
                    has_tui,
                    open_browser,
                    web_port,
                )
            } else {
                info!("no ui was created!");
                drop(wait_ui);
                Ok::<(), std::io::Error>(())
            }
        })?;

    // create a crossbeam channel for massive data exchange
    // with data I called IPC ...
    // in contrast to normal channels crossbeam channels are
    // n:m, so senders can be cloned as well!
    let (ipc_send, ipc_receive) = unbounded::<IPC>();

    // 2 - Net Future
    let net_thread = std::thread::Builder::new()
        .name("net".into())
        .spawn(move || {
            if has_net {
                let sender = Some(tx_net);
                task::block_on(
                    async move { shared::net_search(wait_net, sender, ipc_receive).await },
                )
                .map_err(|error| {
                    std::io::Error::new(
                        std::io::ErrorKind::Other,
                        format!("network error: {}", error),
                    )
                })
            } else {
                info!("no net!");
                drop(wait_net);
                Ok::<(), std::io::Error>(())
            }
        })?;

    // CTRL-C exit handler (is wrapped inside a thread)
    ctrlc::set_handler(move || {
        println!("\n'{}' was manually exited!!!", env!("CARGO_PKG_NAME"));
        process::exit(exitcode::SOFTWARE);
    })
    .map_err(|error| {
        std::io::Error::new(
            std::io::ErrorKind::Other,
            format!(
                "{} terminate signal invokation doesn't work!({:?})",
                env!("CARGO_PKG_NAME"),
                error
            ),
        )
    })?;

    // finished ipc sender reserved before collector takes action
    let ipc_send_finished = ipc_send.clone();

    // the collector
    // but yet this simple bracket to enclose this a little
    {
        trace!("syncing with 2 other threads");
        wait_collector.wait();
        trace!("sync with net and ui done ... collector can start");

        let synced_to_ui_messages = tx_from_collector_to_ui.clone();

        // set up data
        let collection_protected = SArc::new(SMutex::new(Collection::new()));

        // search parallelly
        let output_data = shared::collection_search(
            collection_protected.clone(),
            search_path,
            synced_to_ui_messages,
            has_ui,
        );

        info!("collector finished!!");
        if has_ui || has_net {
            // send own peer and others that are finished
            let memory_used = collection_protected
                .lock()
                .and_then(|collection| Ok(collection.memory()))
                .unwrap_or_else(|_| {
                    error!("locking collection didn't work here!");
                    0
                });

            let mut collection_output = IFCollectionOutputData::from(&output_data);
            // to have not 0 as data size minimum
            collection_output.size_of_data_in_kb = cmp::max(1, (memory_used / 1000) as usize);

            // to others via IPC
            if has_net {
                ipc_send_finished
                    .send(IPC::DoneSearching(collection_output.clone()))
                    .unwrap_or_else(|_| {
                        error!("net has to be up and receiving this send!");
                    });
            }
            // to myself (ui) via UiUpdateMsg
            if has_ui {
                tx_col
                    .send(UiUpdateMsg::PeerSearchFinished(
                        key_keeper::get_p2p_server_id(),
                        collection_output,
                    ))
                    .unwrap_or_else(|e| error!("use one: {}", e));
            }
        }
        if !has_ui {
            collection_protected
                .lock()
                .and_then(|locked_collection| {
                    Ok(locked_collection
                        .print_stats(&key_keeper::get_p2p_server_id(), nr_threads_for_collection))
                })
                .unwrap_or(())
        }
    }

    // look for keeping alive argument if that was chosen
    if keep_alive {
        ui_thread
            .join()
            .unwrap_or_else(|_| {
                // it doesn't matter because we will terminate anyway
                error!("this should be result of ui thread!!");
                Ok(())
            })
            .unwrap();
        if has_ui {
            info!("Stopped ui thread");
        }
        // net thread
        if has_ui {
            // if had a ui , net_thread will stop also after ui quit
            drop(net_thread);
        } else {
            // if didn't have ui, net_thread will continue running
            println!(
                "Search is finished, but net thread is kept running!\nTo stop send break command (ctrl-c)!"
            );
            net_thread
                .join()
                .unwrap_or_else(|_| {
                    // it doesn't matter because we will terminate anyway
                    error!("is this normal when joining net thread???");
                    Ok(())
                })
                .unwrap();
            info!("Stopped net thread");
        }
    } else {
        drop(net_thread);
        drop(ui_thread);
    }
    Ok(())
}
<|endoftext|>


<commit_before>// run-pass
#![feature(repr_simd)]
#![feature(platform_intrinsics)]
#![feature(staged_api)]
#![stable(feature = "foo", since = "1.33.7")]
#![allow(non_camel_case_types)]

#[repr(simd)] struct i8x1(i8);
#[repr(simd)] struct u16x2(u16, u16);
// Make one of them an array type to ensure those also work.
#[repr(simd)] struct f32x4([f32; 4]);

extern "platform-intrinsic" {
    #[rustc_const_stable(feature = "foo", since = "1.3.37")]
    fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
    #[rustc_const_stable(feature = "foo", since = "1.3.37")]
    fn simd_extract<T, U>(x: T, idx: u32) -> U;
}

fn main() {
    {
        const U: i8x1 = i8x1(13);
        const V: i8x1 = unsafe { simd_insert(U, 0_u32, 42_i8) };
        const X0: i8 = V.0;
        const Y0: i8 = unsafe { simd_extract(V, 0) };
        assert_eq!(X0, 42);
        assert_eq!(Y0, 42);
    }
    {
        const U: u16x2 = u16x2(13, 14);
        const V: u16x2 = unsafe { simd_insert(U, 1_u32, 42_u16) };
        const X0: u16 = V.0;
        const X1: u16 = V.1;
        const Y0: u16 = unsafe { simd_extract(V, 0) };
        const Y1: u16 = unsafe { simd_extract(V, 1) };
        assert_eq!(X0, 13);
        assert_eq!(X1, 42);
        assert_eq!(Y0, 13);
        assert_eq!(Y1, 42);
    }
    {
        const U: f32x4 = f32x4([13., 14., 15., 16.]);
        const V: f32x4 = unsafe { simd_insert(U, 1_u32, 42_f32) };
        const X0: f32 = V.0[0];
        const X1: f32 = V.0[1];
        const X2: f32 = V.0[2];
        const X3: f32 = V.0[3];
        const Y0: f32 = unsafe { simd_extract(V, 0) };
        const Y1: f32 = unsafe { simd_extract(V, 1) };
        const Y2: f32 = unsafe { simd_extract(V, 2) };
        const Y3: f32 = unsafe { simd_extract(V, 3) };
        assert_eq!(X0, 13.);
        assert_eq!(X1, 42.);
        assert_eq!(X2, 15.);
        assert_eq!(X3, 16.);
        assert_eq!(Y0, 13.);
        assert_eq!(Y1, 42.);
        assert_eq!(Y2, 15.);
        assert_eq!(Y3, 16.);
    }
}
<commit_msg>CTFE SIMD: also test 1-element array<commit_after>// run-pass
#![feature(repr_simd)]
#![feature(platform_intrinsics)]
#![feature(staged_api)]
#![stable(feature = "foo", since = "1.33.7")]
#![allow(non_camel_case_types)]

#[repr(simd)] struct i8x1(i8);
#[repr(simd)] struct u16x2(u16, u16);
// Make some of them array types to ensure those also work.
#[repr(simd)] struct i8x1_arr([i8; 1]);
#[repr(simd)] struct f32x4([f32; 4]);

extern "platform-intrinsic" {
    #[rustc_const_stable(feature = "foo", since = "1.3.37")]
    fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
    #[rustc_const_stable(feature = "foo", since = "1.3.37")]
    fn simd_extract<T, U>(x: T, idx: u32) -> U;
}

fn main() {
    {
        const U: i8x1 = i8x1(13);
        const V: i8x1 = unsafe { simd_insert(U, 0_u32, 42_i8) };
        const X0: i8 = V.0;
        const Y0: i8 = unsafe { simd_extract(V, 0) };
        assert_eq!(X0, 42);
        assert_eq!(Y0, 42);
    }
    {
        const U: i8x1_arr = i8x1_arr([13]);
        const V: i8x1_arr = unsafe { simd_insert(U, 0_u32, 42_i8) };
        const X0: i8 = V.0[0];
        const Y0: i8 = unsafe { simd_extract(V, 0) };
        assert_eq!(X0, 42);
        assert_eq!(Y0, 42);
    }
    {
        const U: u16x2 = u16x2(13, 14);
        const V: u16x2 = unsafe { simd_insert(U, 1_u32, 42_u16) };
        const X0: u16 = V.0;
        const X1: u16 = V.1;
        const Y0: u16 = unsafe { simd_extract(V, 0) };
        const Y1: u16 = unsafe { simd_extract(V, 1) };
        assert_eq!(X0, 13);
        assert_eq!(X1, 42);
        assert_eq!(Y0, 13);
        assert_eq!(Y1, 42);
    }
    {
        const U: f32x4 = f32x4([13., 14., 15., 16.]);
        const V: f32x4 = unsafe { simd_insert(U, 1_u32, 42_f32) };
        const X0: f32 = V.0[0];
        const X1: f32 = V.0[1];
        const X2: f32 = V.0[2];
        const X3: f32 = V.0[3];
        const Y0: f32 = unsafe { simd_extract(V, 0) };
        const Y1: f32 = unsafe { simd_extract(V, 1) };
        const Y2: f32 = unsafe { simd_extract(V, 2) };
        const Y3: f32 = unsafe { simd_extract(V, 3) };
        assert_eq!(X0, 13.);
        assert_eq!(X1, 42.);
        assert_eq!(X2, 15.);
        assert_eq!(X3, 16.);
        assert_eq!(Y0, 13.);
        assert_eq!(Y1, 42.);
        assert_eq!(Y2, 15.);
        assert_eq!(Y3, 16.);
    }
}
<|endoftext|>