<commit_before>#![crate_name = "platform"]
#![crate_type = "rlib"]
#![no_std]
#![feature(const_fn,lang_items)]

extern crate common;
extern crate drivers;
extern crate hil;
extern crate sam4l;
extern crate support;

use hil::Controller;
use hil::spi_master::SpiMaster;
use drivers::timer::AlarmToTimer;
use drivers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};

// HAL unit tests. To enable a particular unit test, uncomment
// the module here and uncomment the call to start the test in
// the init function below.
//mod gpio_dummy;
//mod spi_dummy;
//mod spi_driver;

#[allow(unused_variables,dead_code)]
pub struct DummyCB {
    val: u8
}

static mut spi_read_buf:  [u8; 64] = [0; 64];
static mut spi_write_buf: [u8; 64] = [0; 64];

pub struct Firestorm {
    chip: sam4l::chip::Sam4l,
    console: &'static drivers::console::Console<'static, sam4l::usart::USART>,
    gpio: &'static drivers::gpio::GPIO<'static, sam4l::gpio::GPIOPin>,
    timer: &'static drivers::timer::TimerDriver<'static, AlarmToTimer<'static,
                                VirtualMuxAlarm<'static, sam4l::ast::Ast>>>,
    tmp006: &'static drivers::tmp006::TMP006<'static, sam4l::i2c::I2CDevice, sam4l::gpio::GPIOPin>,
    spi: &'static drivers::spi::Spi<'static, sam4l::spi::Spi>,
}

impl Firestorm {
    pub unsafe fn service_pending_interrupts(&mut self) {
        self.chip.service_pending_interrupts()
    }

    pub unsafe fn has_pending_interrupts(&mut self) -> bool {
        self.chip.has_pending_interrupts()
    }

    pub fn with_driver<F, R>(&mut self, driver_num: usize, f: F) -> R where
            F: FnOnce(Option<&hil::Driver>) -> R {

        match driver_num {
            0 => f(Some(self.console)),
            1 => f(Some(self.gpio)),
            2 => f(Some(self.tmp006)),
            3 => f(Some(self.timer)),
            4 => f(Some(self.spi)),
            _ => f(None)
        }
    }
}

macro_rules! static_init {
   ($V:ident : $T:ty = $e:expr) => {
        let $V : &mut $T = {
            // Waiting out for size_of to be available at compile-time to avoid
            // hardcoding an abitrary large size...
            static mut BUF : [u8; 1024] = [0; 1024];
            let mut tmp : &mut $T = mem::transmute(&mut BUF);
            *tmp = $e;
            tmp
        };
   }
}

pub unsafe fn init<'a>() -> &'a mut Firestorm {
    use core::mem;

    // Workaround for SB.02 hardware bug
    // TODO(alevy): Get rid of this when we think SB.02 are out of circulation
    sam4l::gpio::PA[14].enable();
    sam4l::gpio::PA[14].set();
    sam4l::gpio::PA[14].enable_output();

    static_init!(console : drivers::console::Console<sam4l::usart::USART> =
                    drivers::console::Console::new(&sam4l::usart::USART3,
                                       &mut drivers::console::WRITE_BUF));
    sam4l::usart::USART3.set_client(console);

    let ast = &sam4l::ast::AST;

    static_init!(mux_alarm : MuxAlarm<'static, sam4l::ast::Ast> =
                    MuxAlarm::new(&sam4l::ast::AST));
    ast.configure(mux_alarm);

    // the i2c address of the device is 0x40
    static_init!(tmp006 : drivers::tmp006::TMP006<'static, sam4l::i2c::I2CDevice, sam4l::gpio::GPIOPin> =
                    drivers::tmp006::TMP006::new(&sam4l::i2c::I2C2, 0x40, &sam4l::gpio::PA[9]));
    sam4l::gpio::PA[9].set_client(tmp006);

    static_init!(virtual_alarm1 : VirtualMuxAlarm<'static, sam4l::ast::Ast> =
                    VirtualMuxAlarm::new(mux_alarm));
    static_init!(vtimer1 : AlarmToTimer<'static,
                                VirtualMuxAlarm<'static, sam4l::ast::Ast>> =
                            AlarmToTimer::new(virtual_alarm1));
    virtual_alarm1.set_client(vtimer1);
    static_init!(timer : drivers::timer::TimerDriver<AlarmToTimer<'static,
                                VirtualMuxAlarm<'static, sam4l::ast::Ast>>> =
                            drivers::timer::TimerDriver::new(vtimer1));
    vtimer1.set_client(timer);

    // Configure SPI pins: CLK, MISO, MOSI, CS3
    sam4l::gpio::PC[ 6].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 4].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 5].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 1].configure(Some(sam4l::gpio::PeripheralFunction::A));
    // Initialize and enable SPI HAL
    static_init!(spi: drivers::spi::Spi<'static, sam4l::spi::Spi> =
                      drivers::spi::Spi::new(&mut sam4l::spi::SPI));
    spi.config_buffers(&mut spi_read_buf, &mut spi_write_buf);

    // set GPIO driver controlling remaining GPIO pins
    static_init!(gpio : drivers::gpio::GPIO<'static, sam4l::gpio::GPIOPin> =
                 drivers::gpio::GPIO::new(&sam4l::gpio::PC[10]));
    /*
            [ &sam4l::gpio::PC[10], &sam4l::gpio::PC[19]
            , &sam4l::gpio::PC[13], &sam4l::gpio::PA[17]
            , &sam4l::gpio::PC[20], &sam4l::gpio::PA[19]
            , &sam4l::gpio::PA[14], &sam4l::gpio::PA[16]
            , &sam4l::gpio::PA[13], &sam4l::gpio::PA[11]
            , &sam4l::gpio::PA[10], &sam4l::gpio::PA[12]
            , &sam4l::gpio::PC[ 9]]
    */
    sam4l::gpio::PC[10].set_client(gpio);
    /*
    sam4l::gpio::PC[19].set_client(firestorm.gpio);
    sam4l::gpio::PC[13].set_client(firestorm.gpio);
    sam4l::gpio::PA[17].set_client(firestorm.gpio);
    sam4l::gpio::PC[20].set_client(firestorm.gpio);
    sam4l::gpio::PA[19].set_client(firestorm.gpio);
    sam4l::gpio::PA[14].set_client(firestorm.gpio);
    sam4l::gpio::PA[16].set_client(firestorm.gpio);
    sam4l::gpio::PA[13].set_client(firestorm.gpio);
    sam4l::gpio::PA[11].set_client(firestorm.gpio);
    sam4l::gpio::PA[10].set_client(firestorm.gpio);
    sam4l::gpio::PA[12].set_client(firestorm.gpio);
    sam4l::gpio::PC[ 9].set_client(firestorm.gpio);
    */

    static_init!(firestorm : Firestorm = Firestorm {
        chip: sam4l::chip::Sam4l::new(),
        console: &*console,
        gpio: gpio,
        timer: timer,
        tmp006: &*tmp006,
        spi: &*spi,
    });

    sam4l::usart::USART3.configure(sam4l::usart::USARTParams {
        //client: &console,
        baud_rate: 115200,
        data_bits: 8,
        parity: hil::uart::Parity::None
    });

    sam4l::gpio::PB[09].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PB[10].configure(Some(sam4l::gpio::PeripheralFunction::A));

    // Configure I2C SDA and SCL pins
    sam4l::gpio::PA[21].configure(Some(sam4l::gpio::PeripheralFunction::E));
    sam4l::gpio::PA[22].configure(Some(sam4l::gpio::PeripheralFunction::E));

    // Uncommenting the following line will cause the device to use the
    // SPI HAL to write [8, 7, 6, 5, 4, 3, 2, 1] once over the SPI then
    // echo the 8 bytes read from the slave continuously.
    //spi_dummy::spi_dummy_test();

    // Uncommenting the following line will toggle the LED whenever the value of
    // Firestorm's pin 8 changes value (e.g., connect a push button to pin 8 and
    // press toggle it).
    //gpio_dummy::gpio_dummy_test();

    sam4l::spi::SPI.set_active_peripheral(sam4l::spi::Peripheral::Peripheral1);
    sam4l::spi::SPI.init(spi as &hil::spi_master::SpiCallback);
    sam4l::spi::SPI.enable();

    firestorm.console.initialize();
    firestorm
}

use core::fmt::Arguments;

#[cfg(not(test))]
#[lang="panic_fmt"]
#[no_mangle]
pub unsafe extern fn rust_begin_unwind(args: Arguments,
    file: &'static str, line: u32) -> ! {

    static mut NUM : usize = 0;

    use hil::uart::UART;
    use core::fmt::*;
    use support::nop;

    NUM += 1;

    sam4l::usart::USART3.configure(sam4l::usart::USARTParams {
        baud_rate: 115200,
        data_bits: 8,
        parity: hil::uart::Parity::None
    });
    sam4l::usart::USART3.enable_tx();

    struct Writer;

    impl Write for Writer {
        fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
            unsafe {
                for c in s.bytes() {
                    sam4l::usart::USART3.send_byte(c);
                }
            }
            Ok(())
        }
    }

    let mut writer = Writer;
    let _ = writer.write_fmt(format_args!("Kernel panic at {}:{}:\r\n\t\"", file, line));
    let _ = write(&mut writer, args);
    let _ = writer.write_str("\"\r\n");

    let led = &sam4l::gpio::PC[10];
    led.enable_output();
    loop {
        for _ in 0..1000000 {
            led.set();
            nop();
        }
        for _ in 0..1000000 {
            led.clear();
            nop();
        }
    }
}

<commit_msg>Working on GPIO driver. Added interrupt capability<commit_after>#![crate_name = "platform"]
#![crate_type = "rlib"]
#![no_std]
#![feature(const_fn,lang_items)]

extern crate common;
extern crate drivers;
extern crate hil;
extern crate sam4l;
extern crate support;

use hil::Controller;
use hil::spi_master::SpiMaster;
use drivers::timer::AlarmToTimer;
use drivers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};

// HAL unit tests. To enable a particular unit test, uncomment
// the module here and uncomment the call to start the test in
// the init function below.
//mod gpio_dummy;
//mod spi_dummy;
//mod spi_driver;

#[allow(unused_variables,dead_code)]
pub struct DummyCB {
    val: u8
}

static mut spi_read_buf:  [u8; 64] = [0; 64];
static mut spi_write_buf: [u8; 64] = [0; 64];

pub struct Firestorm {
    chip: sam4l::chip::Sam4l,
    console: &'static drivers::console::Console<'static, sam4l::usart::USART>,
    gpio: &'static drivers::gpio::GPIO<'static, sam4l::gpio::GPIOPin>,
    timer: &'static drivers::timer::TimerDriver<'static, AlarmToTimer<'static,
                                VirtualMuxAlarm<'static, sam4l::ast::Ast>>>,
    tmp006: &'static drivers::tmp006::TMP006<'static, sam4l::i2c::I2CDevice, sam4l::gpio::GPIOPin>,
    spi: &'static drivers::spi::Spi<'static, sam4l::spi::Spi>,
}

impl Firestorm {
    pub unsafe fn service_pending_interrupts(&mut self) {
        self.chip.service_pending_interrupts()
    }

    pub unsafe fn has_pending_interrupts(&mut self) -> bool {
        self.chip.has_pending_interrupts()
    }

    pub fn with_driver<F, R>(&mut self, driver_num: usize, f: F) -> R where
            F: FnOnce(Option<&hil::Driver>) -> R {

        match driver_num {
            0 => f(Some(self.console)),
            1 => f(Some(self.gpio)),
            2 => f(Some(self.tmp006)),
            3 => f(Some(self.timer)),
            4 => f(Some(self.spi)),
            _ => f(None)
        }
    }
}

macro_rules! static_init {
   ($V:ident : $T:ty = $e:expr) => {
        let $V : &mut $T = {
            // Waiting out for size_of to be available at compile-time to avoid
            // hardcoding an abitrary large size...
            static mut BUF : [u8; 1024] = [0; 1024];
            let mut tmp : &mut $T = mem::transmute(&mut BUF);
            *tmp = $e;
            tmp
        };
   }
}

pub unsafe fn init<'a>() -> &'a mut Firestorm {
    use core::mem;

    // Workaround for SB.02 hardware bug
    // TODO(alevy): Get rid of this when we think SB.02 are out of circulation
    sam4l::gpio::PA[14].enable();
    sam4l::gpio::PA[14].set();
    sam4l::gpio::PA[14].enable_output();

    static_init!(console : drivers::console::Console<sam4l::usart::USART> =
                    drivers::console::Console::new(&sam4l::usart::USART3,
                                       &mut drivers::console::WRITE_BUF));
    sam4l::usart::USART3.set_client(console);

    let ast = &sam4l::ast::AST;

    static_init!(mux_alarm : MuxAlarm<'static, sam4l::ast::Ast> =
                    MuxAlarm::new(&sam4l::ast::AST));
    ast.configure(mux_alarm);

    // the i2c address of the device is 0x40
    static_init!(tmp006 : drivers::tmp006::TMP006<'static, sam4l::i2c::I2CDevice, sam4l::gpio::GPIOPin> =
                    drivers::tmp006::TMP006::new(&sam4l::i2c::I2C2, 0x40, &sam4l::gpio::PA[9]));
    sam4l::gpio::PA[9].set_client(tmp006);

    static_init!(virtual_alarm1 : VirtualMuxAlarm<'static, sam4l::ast::Ast> =
                    VirtualMuxAlarm::new(mux_alarm));
    static_init!(vtimer1 : AlarmToTimer<'static,
                                VirtualMuxAlarm<'static, sam4l::ast::Ast>> =
                            AlarmToTimer::new(virtual_alarm1));
    virtual_alarm1.set_client(vtimer1);
    static_init!(timer : drivers::timer::TimerDriver<AlarmToTimer<'static,
                                VirtualMuxAlarm<'static, sam4l::ast::Ast>>> =
                            drivers::timer::TimerDriver::new(vtimer1));
    vtimer1.set_client(timer);

    // Configure SPI pins: CLK, MISO, MOSI, CS3
    sam4l::gpio::PC[ 6].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 4].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 5].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 1].configure(Some(sam4l::gpio::PeripheralFunction::A));
    // Initialize and enable SPI HAL
    static_init!(spi: drivers::spi::Spi<'static, sam4l::spi::Spi> =
                      drivers::spi::Spi::new(&mut sam4l::spi::SPI));
    spi.config_buffers(&mut spi_read_buf, &mut spi_write_buf);

    // set GPIO driver controlling remaining GPIO pins
    static_init!(gpio : drivers::gpio::GPIO<'static, sam4l::gpio::GPIOPin> =
                 drivers::gpio::GPIO::new(&sam4l::gpio::PC[10]));
    sam4l::gpio::PC[10].set_client(gpio);
    /*
    sam4l::gpio::PC[19].set_client(firestorm.gpio);
    sam4l::gpio::PC[13].set_client(firestorm.gpio);
    sam4l::gpio::PA[17].set_client(firestorm.gpio);
    sam4l::gpio::PC[20].set_client(firestorm.gpio);
    sam4l::gpio::PA[19].set_client(firestorm.gpio);
    sam4l::gpio::PA[14].set_client(firestorm.gpio);
    sam4l::gpio::PA[16].set_client(firestorm.gpio);
    sam4l::gpio::PA[13].set_client(firestorm.gpio);
    sam4l::gpio::PA[11].set_client(firestorm.gpio);
    sam4l::gpio::PA[10].set_client(firestorm.gpio);
    sam4l::gpio::PA[12].set_client(firestorm.gpio);
    sam4l::gpio::PC[ 9].set_client(firestorm.gpio);
    */

    static_init!(firestorm : Firestorm = Firestorm {
        chip: sam4l::chip::Sam4l::new(),
        console: &*console,
        gpio: gpio,
        timer: timer,
        tmp006: &*tmp006,
        spi: &*spi,
    });

    sam4l::usart::USART3.configure(sam4l::usart::USARTParams {
        //client: &console,
        baud_rate: 115200,
        data_bits: 8,
        parity: hil::uart::Parity::None
    });

    sam4l::gpio::PB[09].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PB[10].configure(Some(sam4l::gpio::PeripheralFunction::A));

    // Configure I2C SDA and SCL pins
    sam4l::gpio::PA[21].configure(Some(sam4l::gpio::PeripheralFunction::E));
    sam4l::gpio::PA[22].configure(Some(sam4l::gpio::PeripheralFunction::E));

    // Uncommenting the following line will cause the device to use the
    // SPI HAL to write [8, 7, 6, 5, 4, 3, 2, 1] once over the SPI then
    // echo the 8 bytes read from the slave continuously.
    //spi_dummy::spi_dummy_test();

    // Uncommenting the following line will toggle the LED whenever the value of
    // Firestorm's pin 8 changes value (e.g., connect a push button to pin 8 and
    // press toggle it).
    //gpio_dummy::gpio_dummy_test();

    sam4l::spi::SPI.set_active_peripheral(sam4l::spi::Peripheral::Peripheral1);
    sam4l::spi::SPI.init(spi as &hil::spi_master::SpiCallback);
    sam4l::spi::SPI.enable();

    firestorm.console.initialize();
    firestorm
}

use core::fmt::Arguments;

#[cfg(not(test))]
#[lang="panic_fmt"]
#[no_mangle]
pub unsafe extern fn rust_begin_unwind(args: Arguments,
    file: &'static str, line: u32) -> ! {

    static mut NUM : usize = 0;

    use hil::uart::UART;
    use core::fmt::*;
    use support::nop;

    NUM += 1;

    sam4l::usart::USART3.configure(sam4l::usart::USARTParams {
        baud_rate: 115200,
        data_bits: 8,
        parity: hil::uart::Parity::None
    });
    sam4l::usart::USART3.enable_tx();

    struct Writer;

    impl Write for Writer {
        fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
            unsafe {
                for c in s.bytes() {
                    sam4l::usart::USART3.send_byte(c);
                }
            }
            Ok(())
        }
    }

    let mut writer = Writer;
    let _ = writer.write_fmt(format_args!("Kernel panic at {}:{}:\r\n\t\"", file, line));
    let _ = write(&mut writer, args);
    let _ = writer.write_str("\"\r\n");

    let led = &sam4l::gpio::PC[10];
    led.enable_output();
    loop {
        for _ in 0..1000000 {
            led.set();
            nop();
        }
        for _ in 0..1000000 {
            led.clear();
            nop();
        }
    }
}

<|endoftext|>


<commit_before>use futures::{Poll, Future, Async, BoxFuture};
use tokio_service::Service;
use store::Store;
use {LogPos, Error};
use std::net::SocketAddr;
use std::io;
use std::mem;
use replica::{ReplicaRequest, ReplicaResponse, LogEntry};

enum ReplicatorState<S: Store, D>
    where D: DownstreamService
{
    Idle,
    Fetching(S::FetchFut),
    Forwarding(D::Future),
}

pub trait DownstreamService {
    type Future: Future<Item = ReplicaResponse, Error = io::Error>;
}

impl<D> DownstreamService for D
    where D: Service<Request = (SocketAddr, ReplicaRequest),
                     Response = ReplicaResponse,
                     Error = io::Error,
                     Future = BoxFuture<ReplicaResponse, io::Error>>
{
    type Future = D::Future;
}

pub struct Replicator<S: Store, D: DownstreamService> {
    store: S,
    downstream: D,
    last_seen_seq: LogPos,
    downstream_addr: Option<SocketAddr>,
    state: ReplicatorState<S, D>,
}

impl<S: Store, D: DownstreamService> Replicator<S, D> {
    pub fn new(store: S, downstream: D) -> Self {
        Replicator {
            store: store,
            downstream: downstream,
            last_seen_seq: LogPos::zero(),
            downstream_addr: None,
            state: ReplicatorState::Idle,
        }
    }
}

impl<S: Store, D: DownstreamService> Drop for Replicator<S, D> {
    fn drop(&mut self) {
        debug!("Drop Replicator");
    }
}

impl<S: Store, D> Future for Replicator<S, D>
    where S: Store,
          D: Service<Request = (SocketAddr, ReplicaRequest),
                     Response = ReplicaResponse,
                     Error = io::Error,
                     Future = BoxFuture<ReplicaResponse, io::Error>>
{
    type Item = ();
    type Error = Error;
    fn poll(&mut self) -> Poll<(), Error> {
        debug!("Replicator#poll");
        loop {
            match mem::replace(&mut self.state, ReplicatorState::Idle) {
                ReplicatorState::Idle => {
                    debug!("Idle, fetching after: {:?}", self.last_seen_seq);
                    let fetch_f = self.store.fetch_next(self.last_seen_seq);
                    self.state = ReplicatorState::Fetching(fetch_f);
                }
                // Now, what have we learnt from this, children? Surely it's
                // that because we're forwarding LogEntries at least, we
                // should make it easy to get a LogEntry into/out of the
                // store, rather than having to futz around with serialisation
                // rubbish.
                ReplicatorState::Fetching(mut fetch_f) => {
                    debug!("Fetching");
                    match try!(fetch_f.poll()) {
                        Async::NotReady => {
                            self.state = ReplicatorState::Fetching(fetch_f);
                            return Ok(Async::NotReady);
                        }
                        Async::Ready((off, val)) => {
                            debug!("Fetched: {:?}", (&off, &val));
                            if let &LogEntry::Config(ref conf) = &val {
                                debug!("logged Config message: {:?}", conf);
                                // FIXME: Well, this is blatantly wrong.
                                self.downstream_addr = Some(conf.head);
                            };

                            if let Some(addr) = self.downstream_addr {
                                debug!("Forward {:?} to: {:?}", off, addr);
                                // XXX: Symmetry with ReplClient?
                                let req = ReplicaRequest::AppendLogEntry {
                                    assumed_offset: self.last_seen_seq,
                                    entry_offset: off,
                                    datum: val,
                                };
                                let f = self.downstream.call((addr, req));
                                self.state = ReplicatorState::Forwarding(f);
                            } else {
                                debug!("No downstream at {:?}", off);
                            }
                            self.last_seen_seq = off;
                        }
                    }
                }
                ReplicatorState::Forwarding(mut f) => {
                    match try!(f.poll()) {
                        Async::NotReady => {
                            self.state = ReplicatorState::Forwarding(f);
                            return Ok(Async::NotReady);
                        }
                        Async::Ready(ReplicaResponse::Done(pos)) => {
                            debug!("woo! {:?}", pos);
                        }
                        Async::Ready(ReplicaResponse::BadSequence(pos)) => {
                            debug!("Bad sequence: resetting to {:?}", pos);
                            self.last_seen_seq = pos;
                        }
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use futures::{self, Future, BoxFuture, Async};
    use futures::stream::Stream;
    use service::Service;
    use tokio::channel;
    use replica::LogPos;
    use store::{RamStore, Store};
    use replica::{ReplicaRequest, ReplicaResponse, LogEntry, HostConfig};
    use std::net::SocketAddr;
    use super::*;
    use tokio::reactor::Core;
    use std::time::Duration;
    use std::io;
    use tokio_timer;
    use env_logger;

    struct MyMagicalDownstream {
        send: channel::Sender<((SocketAddr, ReplicaRequest), futures::Complete<ReplicaResponse>)>,
    }

    impl Service for MyMagicalDownstream {
        type Request = (SocketAddr, ReplicaRequest);
        type Response = ReplicaResponse;
        type Error = io::Error;
        type Future = BoxFuture<ReplicaResponse, io::Error>;
        fn poll_ready(&self) -> Async<()> {
            Async::Ready(())
        }
        fn call(&self, req: Self::Request) -> Self::Future {
            let (c, p) = futures::oneshot();
            match self.send.send((req, c)) {
                Ok(()) => (),
                Err(e) => return futures::failed(e).boxed(),
            };
            p.map_err(|_| io::Error::new(io::ErrorKind::BrokenPipe, "broken pipe"))
                .boxed()
        }
    }

    #[test]
    fn should_start_replicating_to_downstream_on_committed_config_message() {
        env_logger::init().unwrap_or(());
        let store = RamStore::new();
        let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();

        let mut core = Core::new().expect("core::new");
        let (tx, rx) = channel::channel(&core.handle()).expect("channel");

        let downstream = MyMagicalDownstream { send: tx };

        let replica = Replicator::new(store.clone(), downstream);

        core.handle().spawn(replica.map_err(|e| panic!("Replicator failed!: {:?}", e)));
        debug!("Spawned replica task");

        let head_addr = "1.2.3.4:5".parse().expect("parse");

        let config: HostConfig<::std::net::SocketAddr> = HostConfig {
            head: head_addr,
            tail: "1.2.3.6:7".parse().expect("parse"),
        };
        let off = LogPos::zero();
        let _ = append_entry(&store, &mut core, off, LogEntry::Config(config.clone()));

        let f = timer.timeout(rx.into_future().map_err(|(e, _)| e),
                              Duration::from_millis(1000));
        debug!("wait for stub message");
        let (data, _rx) = core.run(f).expect("receive downstream");
        let ((addr, msg), _completer) = data.expect("Some message");
        println!("Some: {:?}", (&addr, &msg));
        let (_assumed, _off, entry) = match msg {
            ReplicaRequest::AppendLogEntry { assumed_offset, entry_offset, datum } => {
                (assumed_offset, entry_offset, datum)
            }
        };
        assert_eq!((addr, entry), (head_addr, LogEntry::Config(config)));
    }

    #[test]
    fn should_send_next_log_entry_on_okay_from_downstream() {
        env_logger::init().unwrap_or(());
        let store = RamStore::new();
        let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();

        let mut core = Core::new().expect("core::new");
        let (tx, rx) = channel::channel(&core.handle()).expect("channel");

        let downstream = MyMagicalDownstream { send: tx };

        let replica = Replicator::new(store.clone(), downstream);

        core.handle().spawn(replica.map_err(|e| panic!("Replicator failed!: {:?}", e)));
        debug!("Spawned replica task");

        let head_addr = "1.2.3.4:5".parse().expect("parse");

        let config: HostConfig<::std::net::SocketAddr> = HostConfig {
            head: head_addr,
            tail: "1.2.3.6:7".parse().expect("parse"),
        };

        let off0 = append_entry(&store,
                                &mut core,
                                LogPos::zero(),
                                LogEntry::Config(config.clone()));
        let _off1 = append_entry(&store,
                                 &mut core,
                                 off0,
                                 LogEntry::Data(b"Hello world!".to_vec()));

        let f = timer.timeout(rx.into_future().map_err(|(e, _)| e),
                              Duration::from_millis(1000));
        debug!("wait for stub message");
        let (data, rx) = core.run(f).expect("receive downstream");
        let ((addr, msg), completer) = data.expect("Some message");
        println!("Some: {:?}", (&addr, &msg));
        // Expect that the target at `head_addr` receives a set of replication messages.
        let (_assumed0, off0, _entry0) = match msg {
            ReplicaRequest::AppendLogEntry { assumed_offset, entry_offset, datum } => {
                (assumed_offset, entry_offset, datum)
            }
        };

        completer.complete(ReplicaResponse::Done(off0));

        let f = timer.timeout(rx.into_future().map_err(|(e, _)| e),
                              Duration::from_millis(1000));
        debug!("wait for stub message");
        let (data, _rx) = core.run(f).expect("receive downstream");
        let ((addr, msg), _completer) = data.expect("Some message");
        println!("Some: {:?}", (&addr, &msg));
        // Expect that the target at `head_addr` receives a set of replication messages.
        let (assumed1, off1, entry1) = match msg {
            ReplicaRequest::AppendLogEntry { assumed_offset, entry_offset, datum } => {
                (assumed_offset, entry_offset, datum)
            }
        };

        assert_eq!((addr, assumed1, entry1),
                   (head_addr, off0, LogEntry::Data(b"Hello world!".to_vec())));
        assert!(off1 > assumed1);
    }

    #[test]
    fn should_restart_replication_on_badsequence_from_downstream() {
        env_logger::init().unwrap_or(());
        let store = RamStore::new();
        let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();

        let mut core = Core::new().expect("core::new");
        let (tx, rx) = channel::channel(&core.handle()).expect("channel");

        let downstream = MyMagicalDownstream { send: tx };

        let replica = Replicator::new(store.clone(), downstream);

        core.handle().spawn(replica.map_err(|e| panic!("Replicator failed!: {:?}", e)));
        debug!("Spawned replica task");

        let head_addr = "1.2.3.4:5".parse().expect("parse");

        let config: HostConfig<::std::net::SocketAddr> = HostConfig {
            head: head_addr,
            tail: "1.2.3.6:7".parse().expect("parse"),
        };

        let log_off = LogPos::zero();
        let log_off0 = append_entry(&store, &mut core, log_off, LogEntry::Config(config.clone()));
        let log_off1 = append_entry(&store,
                                    &mut core,
                                    log_off0,
                                    LogEntry::Data(b"Hello".to_vec()));
        let log_off2 = append_entry(&store,
                                    &mut core,
                                    log_off1,
                                    LogEntry::Data(b"world!".to_vec()));

        let f = timer.timeout(rx.into_future().map_err(|(e, _)| e),
                              Duration::from_millis(1000));
        debug!("wait for stub message");
        let (data, rx) = core.run(f).expect("receive downstream");
        let ((addr, msg), completer) = data.expect("Some message");
        println!("Some: {:?}", (&addr, &msg));
        // Expect that the target at `head_addr` receives a set of replication messages.
        let (_assumed0, _off0, _entry0) = match msg {
            ReplicaRequest::AppendLogEntry { assumed_offset, entry_offset, datum } => {
                (assumed_offset, entry_offset, datum)
            }
        };

        // So we expect the delivery of "world!"
        let resp = ReplicaResponse::BadSequence(log_off1);
        println!("Respond with: {:?}", resp);
        completer.complete(resp);

        let f = timer.timeout(rx.into_future().map_err(|(e, _)| e),
                              Duration::from_millis(1000));
        debug!("wait for stub message");
        let (data, _rx) = core.run(f).expect("receive downstream");
        let ((addr, msg), _completer) = data.expect("Some message");
        println!("Some: {:?}", (&addr, &msg));
        // Expect that the target at `head_addr` receives a set of replication messages.
        let (assumed1, off1, entry1) = match msg {
            ReplicaRequest::AppendLogEntry { assumed_offset, entry_offset, datum } => {
                (assumed_offset, entry_offset, datum)
            }
        };

        assert_eq!((addr, assumed1, off1, entry1),
                   (head_addr, log_off1, log_off2, LogEntry::Data(b"world!".to_vec())));
    }

    fn append_entry<S: Store>(store: &S, core: &mut Core, off: LogPos, entry: LogEntry) -> LogPos {
        let next = off.next();
        debug!("append config message {:?} -> {:?}", off, next);
        core.run(store.append_entry(off, next, entry))
            .expect("append");
        next
    }
}
<commit_msg>Convenience function for taking next message.<commit_after>use futures::{Poll, Future, Async, BoxFuture};
use tokio_service::Service;
use store::Store;
use {LogPos, Error};
use std::net::SocketAddr;
use std::io;
use std::mem;
use replica::{ReplicaRequest, ReplicaResponse, LogEntry};

enum ReplicatorState<S: Store, D>
    where D: DownstreamService
{
    Idle,
    Fetching(S::FetchFut),
    Forwarding(D::Future),
}

pub trait DownstreamService {
    type Future: Future<Item = ReplicaResponse, Error = io::Error>;
}

impl<D> DownstreamService for D
    where D: Service<Request = (SocketAddr, ReplicaRequest),
                     Response = ReplicaResponse,
                     Error = io::Error,
                     Future = BoxFuture<ReplicaResponse, io::Error>>
{
    type Future = D::Future;
}

pub struct Replicator<S: Store, D: DownstreamService> {
    store: S,
    downstream: D,
    last_seen_seq: LogPos,
    downstream_addr: Option<SocketAddr>,
    state: ReplicatorState<S, D>,
}

impl<S: Store, D: DownstreamService> Replicator<S, D> {
    pub fn new(store: S, downstream: D) -> Self {
        Replicator {
            store: store,
            downstream: downstream,
            last_seen_seq: LogPos::zero(),
            downstream_addr: None,
            state: ReplicatorState::Idle,
        }
    }
}

impl<S: Store, D: DownstreamService> Drop for Replicator<S, D> {
    fn drop(&mut self) {
        debug!("Drop Replicator");
    }
}

impl<S: Store, D> Future for Replicator<S, D>
    where S: Store,
          D: Service<Request = (SocketAddr, ReplicaRequest),
                     Response = ReplicaResponse,
                     Error = io::Error,
                     Future = BoxFuture<ReplicaResponse, io::Error>>
{
    type Item = ();
    type Error = Error;
    fn poll(&mut self) -> Poll<(), Error> {
        debug!("Replicator#poll");
        loop {
            match mem::replace(&mut self.state, ReplicatorState::Idle) {
                ReplicatorState::Idle => {
                    debug!("Idle, fetching after: {:?}", self.last_seen_seq);
                    let fetch_f = self.store.fetch_next(self.last_seen_seq);
                    self.state = ReplicatorState::Fetching(fetch_f);
                }
                // Now, what have we learnt from this, children? Surely it's
                // that because we're forwarding LogEntries at least, we
                // should make it easy to get a LogEntry into/out of the
                // store, rather than having to futz around with serialisation
                // rubbish.
                ReplicatorState::Fetching(mut fetch_f) => {
                    debug!("Fetching");
                    match try!(fetch_f.poll()) {
                        Async::NotReady => {
                            self.state = ReplicatorState::Fetching(fetch_f);
                            return Ok(Async::NotReady);
                        }
                        Async::Ready((off, val)) => {
                            debug!("Fetched: {:?}", (&off, &val));
                            if let &LogEntry::Config(ref conf) = &val {
                                debug!("logged Config message: {:?}", conf);
                                // FIXME: Well, this is blatantly wrong.
                                self.downstream_addr = Some(conf.head);
                            };

                            if let Some(addr) = self.downstream_addr {
                                debug!("Forward {:?} to: {:?}", off, addr);
                                // XXX: Symmetry with ReplClient?
                                let req = ReplicaRequest::AppendLogEntry {
                                    assumed_offset: self.last_seen_seq,
                                    entry_offset: off,
                                    datum: val,
                                };
                                let f = self.downstream.call((addr, req));
                                self.state = ReplicatorState::Forwarding(f);
                            } else {
                                debug!("No downstream at {:?}", off);
                            }
                            self.last_seen_seq = off;
                        }
                    }
                }
                ReplicatorState::Forwarding(mut f) => {
                    match try!(f.poll()) {
                        Async::NotReady => {
                            self.state = ReplicatorState::Forwarding(f);
                            return Ok(Async::NotReady);
                        }
                        Async::Ready(ReplicaResponse::Done(pos)) => {
                            debug!("woo! {:?}", pos);
                        }
                        Async::Ready(ReplicaResponse::BadSequence(pos)) => {
                            debug!("Bad sequence: resetting to {:?}", pos);
                            self.last_seen_seq = pos;
                        }
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use futures::{self, Future, BoxFuture, Async};
    use futures::stream::Stream;
    use service::Service;
    use tokio::channel;
    use replica::LogPos;
    use store::{RamStore, Store};
    use replica::{ReplicaRequest, ReplicaResponse, LogEntry, HostConfig};
    use std::net::SocketAddr;
    use super::*;
    use tokio::reactor::Core;
    use std::time::Duration;
    use std::io;
    use tokio_timer;
    use env_logger;

    type MessageType = ((SocketAddr, ReplicaRequest), futures::Complete<ReplicaResponse>);
    struct MyMagicalDownstream {
        send: channel::Sender<MessageType>,
    }

    impl Service for MyMagicalDownstream {
        type Request = (SocketAddr, ReplicaRequest);
        type Response = ReplicaResponse;
        type Error = io::Error;
        type Future = BoxFuture<ReplicaResponse, io::Error>;
        fn poll_ready(&self) -> Async<()> {
            Async::Ready(())
        }
        fn call(&self, req: Self::Request) -> Self::Future {
            let (c, p) = futures::oneshot();
            match self.send.send((req, c)) {
                Ok(()) => (),
                Err(e) => return futures::failed(e).boxed(),
            };
            p.map_err(|_| io::Error::new(io::ErrorKind::BrokenPipe, "broken pipe"))
                .boxed()
        }
    }

    #[test]
    fn should_start_replicating_to_downstream_on_committed_config_message() {
        env_logger::init().unwrap_or(());
        let store = RamStore::new();
        let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();

        let mut core = Core::new().expect("core::new");
        let (tx, rx) = channel::channel(&core.handle()).expect("channel");

        let downstream = MyMagicalDownstream { send: tx };

        let replica = Replicator::new(store.clone(), downstream);

        core.handle().spawn(replica.map_err(|e| panic!("Replicator failed!: {:?}", e)));
        debug!("Spawned replica task");

        let head_addr = "1.2.3.4:5".parse().expect("parse");

        let config: HostConfig<::std::net::SocketAddr> = HostConfig {
            head: head_addr,
            tail: "1.2.3.6:7".parse().expect("parse"),
        };
        let off = LogPos::zero();
        let _ = append_entry(&store, &mut core, off, LogEntry::Config(config.clone()));

        let (_rx, _response, _assumed0, _off0, entry0) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        assert_eq!(entry0, LogEntry::Config(config));
    }

    #[test]
    fn should_send_next_log_entry_on_okay_from_downstream() {
        env_logger::init().unwrap_or(());
        let store = RamStore::new();
        let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();

        let mut core = Core::new().expect("core::new");
        let (tx, rx) = channel::channel(&core.handle()).expect("channel");

        let downstream = MyMagicalDownstream { send: tx };

        let replica = Replicator::new(store.clone(), downstream);

        core.handle().spawn(replica.map_err(|e| panic!("Replicator failed!: {:?}", e)));
        debug!("Spawned replica task");

        let head_addr = "1.2.3.4:5".parse().expect("parse");

        let config: HostConfig<::std::net::SocketAddr> = HostConfig {
            head: head_addr,
            tail: "1.2.3.6:7".parse().expect("parse"),
        };

        let off0 = append_entry(&store,
                                &mut core,
                                LogPos::zero(),
                                LogEntry::Config(config.clone()));
        let _off1 = append_entry(&store,
                                 &mut core,
                                 off0,
                                 LogEntry::Data(b"Hello world!".to_vec()));

        let (rx, response, _assumed0, off0, _entry0) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        response.complete(ReplicaResponse::Done(off0));

        let (_rx, _response, assumed1, off1, entry1) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        assert_eq!((assumed1, entry1),
                   (off0, LogEntry::Data(b"Hello world!".to_vec())));
        assert!(off1 > assumed1);
    }

    #[test]
    fn should_restart_replication_on_badsequence_from_downstream() {
        env_logger::init().unwrap_or(());
        let store = RamStore::new();
        let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();

        let mut core = Core::new().expect("core::new");
        let (tx, rx) = channel::channel(&core.handle()).expect("channel");

        let downstream = MyMagicalDownstream { send: tx };

        let replica = Replicator::new(store.clone(), downstream);

        core.handle().spawn(replica.map_err(|e| panic!("Replicator failed!: {:?}", e)));
        debug!("Spawned replica task");

        let head_addr = "1.2.3.4:5".parse().expect("parse");

        let config: HostConfig<::std::net::SocketAddr> = HostConfig {
            head: head_addr,
            tail: "1.2.3.6:7".parse().expect("parse"),
        };

        let log_off = LogPos::zero();
        let log_off0 = append_entry(&store, &mut core, log_off, LogEntry::Config(config.clone()));
        let log_off1 = append_entry(&store,
                                    &mut core,
                                    log_off0,
                                    LogEntry::Data(b"Hello".to_vec()));
        let log_off2 = append_entry(&store,
                                    &mut core,
                                    log_off1,
                                    LogEntry::Data(b"world!".to_vec()));

        let (rx, response, _assumed0, _off0, _entry0) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        // So we expect the delivery of "world!"
        let resp = ReplicaResponse::BadSequence(log_off1);
        println!("Respond with: {:?}", resp);
        response.complete(resp);
        let (_rx, _response, assumed1, off1, entry1) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        assert_eq!((assumed1, off1, entry1),
                   (log_off1, log_off2, LogEntry::Data(b"world!".to_vec())));
    }

    fn append_entry<S: Store>(store: &S, core: &mut Core, off: LogPos, entry: LogEntry) -> LogPos {
        let next = off.next();
        debug!("append config message {:?} -> {:?}", off, next);
        core.run(store.append_entry(off, next, entry))
            .expect("append");
        next
    }

    fn take_next_entry(rx: channel::Receiver<MessageType>,
                       target: &SocketAddr,
                       core: &mut Core,
                       timer: &tokio_timer::Timer)
                       -> (channel::Receiver<MessageType>,
                           futures::Complete<ReplicaResponse>,
                           LogPos,
                           LogPos,
                           LogEntry) {
        let f = timer.timeout(rx.into_future().map_err(|(e, _)| e),
                              Duration::from_millis(1000));
        debug!("wait for stub message");
        let (data, rx) = core.run(f).expect("receive downstream");
        let ((addr, msg), response) = data.expect("Some message");
        assert_eq!(&addr, target);
        println!("Some: {:?}", (&addr, &msg));
        // Expect that the target at `head_addr` receives a set of replication messages.
        match msg {
            ReplicaRequest::AppendLogEntry { assumed_offset, entry_offset, datum } => {
                (rx, response, assumed_offset, entry_offset, datum)
            }
        }
    }
}
<|endoftext|>


<commit_before>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be embedded into higher-level code generators.

mod gen;
mod syntax;

pub use crate::gen::Opt;
use proc_macro2::TokenStream;

pub use crate::gen::{Error, Result};

/// Results of code generation.
pub struct GeneratedCode {
    /// The bytes of a C++ header file.
    pub header: Vec<u8>,
    /// The bytes of a C++ implementation file (e.g. .cc, cpp etc.)
    pub cxx: Vec<u8>,
}

/// Generate C++ bindings code from a Rust token stream. This should be a Rust
/// token stream which somewhere contains a `#[cxx::bridge] mod {}`.
pub fn generate_header_and_cc(rust_source: TokenStream, opt: Opt) -> Result<GeneratedCode> {
    let syntax = syn::parse2(rust_source)?;
    match gen::generate(syntax, opt, true, true) {
        Ok((Some(header), Some(cxx))) => Ok(GeneratedCode { header, cxx }),
        Err(err) => Err(err),
        _ => panic!("Unexpected generation"),
    }
}
<commit_msg>Ignore cxx-gen not using format_err<commit_after>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be embedded into higher-level code generators.

#![allow(dead_code)]

mod gen;
mod syntax;

pub use crate::gen::Opt;
use proc_macro2::TokenStream;

pub use crate::gen::{Error, Result};

/// Results of code generation.
pub struct GeneratedCode {
    /// The bytes of a C++ header file.
    pub header: Vec<u8>,
    /// The bytes of a C++ implementation file (e.g. .cc, cpp etc.)
    pub cxx: Vec<u8>,
}

/// Generate C++ bindings code from a Rust token stream. This should be a Rust
/// token stream which somewhere contains a `#[cxx::bridge] mod {}`.
pub fn generate_header_and_cc(rust_source: TokenStream, opt: Opt) -> Result<GeneratedCode> {
    let syntax = syn::parse2(rust_source)?;
    match gen::generate(syntax, opt, true, true) {
        Ok((Some(header), Some(cxx))) => Ok(GeneratedCode { header, cxx }),
        Err(err) => Err(err),
        _ => panic!("Unexpected generation"),
    }
}
<|endoftext|>


<commit_before>/// Tangle request message.
///
/// ```javascript
/// ["chat.send_message", {"request_id": "123"}, ["text"], {}]
/// ```
use std::str;
use std::ascii::AsciiExt;
use std::collections::BTreeMap;

use rustc_serialize::json::{self, Json};
use rustc_serialize::{Encodable, Encoder};

pub type Meta = BTreeMap<String, Json>;
pub type Args = Vec<Json>;
pub type Kwargs = BTreeMap<String, Json>;

quick_error! {
    #[derive(Debug, PartialEq)]
    pub enum ValidationError {
        /// Invalid message length;
        InvalidLength {}
        /// Invalid method ("tangle." or contains ".");
        InvalidMethod {}
        /// request_id is missing or invalid in request_meta object;
        InvalidRequestId {}
        /// user_id is missing or invalid in request_meta object;
        InvalidUserId {}
        /// Array of args expected;
        ArrayExpected {}
        /// Meta/Kwargs object expected;
        ObjectExpected {}
    }
}

/// Decode Websocket json message into Meta & Message structs.
pub fn decode_message(s: &str)
    -> Result<(String, Meta, Args, Kwargs), ValidationError>
{
    use self::ValidationError::*;
    let valid_method = |m: &str| {
        !m.starts_with("tangle.") &&
        m.chars().all(|c| c.is_ascii() &&
            (c.is_alphanumeric() || c == '-' || c == '_' || c == '.' ))
    };
    match Json::from_str(s) {
        Ok(Json::Array(mut message)) => {
            use rustc_serialize::json::Json::*;

            if message.len() != 4 {
                return Err(InvalidLength)
            }
            let kwargs = match message.pop() {
                Some(Object(kwargs)) => kwargs,
                _ => return Err(ObjectExpected),
            };
            let args = match message.pop() {
                Some(Array(args)) => args,
                _ => return Err(ArrayExpected),
            };
            let meta = match message.pop() {
                Some(Object(meta)) => meta,
                _ => return Err(ObjectExpected),
            };
            match meta.get("request_id".into()) {
                Some(&Json::String(ref s)) if s.len() > 0 => {}
                Some(&Json::I64(_)) |
                    Some(&Json::U64(_)) |
                    Some(&Json::F64(_)) => {},
                _ => return Err(InvalidRequestId),
            };
            let method = match message.pop() {
                Some(Json::String(method)) => {
                    if !valid_method(&method) {
                        return Err(InvalidMethod);
                    }
                    method
                }
                _ => return Err(InvalidMethod),
            };
            Ok((method, meta, args, kwargs))
        }
        _ => Err(ArrayExpected),
    }
}

/// Returns true if Meta object contains 'active' key and
/// it either set to true or uint timeout (in seconds).
///
/// NOTE: we support bool for compatibility with tangle
pub fn get_active(meta: &Meta) -> Option<Option<u64>>   // XXX
{
    let duration = meta.get(&"active".to_string());
    match duration {
        Some(&Json::U64(v)) => Some(Some(v)),
        Some(&Json::Boolean(true)) => Some(None),
        _ => None,
    }
}

#[derive(RustcEncodable)]
pub struct AuthData {
    pub http_cookie: Option<String>,
    pub http_authorization: Option<String>,
    pub url_querystring: String,
}

// Private tools

pub struct Auth<'a>(pub &'a String, pub &'a AuthData);

impl<'a> Encodable for Auth<'a> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_seq(3, |s| {
            s.emit_seq_elt(0, |s| {
                s.emit_map(1, |s| {
                    s.emit_map_elt_key(0, |s| s.emit_str("connection_id"))?;
                    s.emit_map_elt_val(0, |s| self.0.encode(s))?;
                    Ok(())
                })?;
                Ok(())
            })?;
            s.emit_seq_elt(1, |s| s.emit_seq(0, |_| Ok(())))?;
            s.emit_seq_elt(2, |s| self.1.encode(s))?;
            Ok(())
        })?;
        Ok(())
    }
}

pub struct Call<'a>(pub &'a Meta, pub &'a String, pub &'a Args, pub &'a Kwargs);

impl<'a> Encodable for Call<'a> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_seq(3, |s| {
            s.emit_seq_elt(0, |s| {
                let n = match self.0.get("connection_id") {
                    Some(_) => self.0.len(),
                    None => self.0.len() + 1,
                };
                s.emit_map(n, |s| {
                    s.emit_map_elt_key(0, |s| s.emit_str("connection_id"))?;
                    s.emit_map_elt_val(0, |s| self.1.encode(s))?;
                    let m = self.0.iter()
                        .filter(|&(&ref k, _)| k != "connection_id")
                        .enumerate();
                    for (i, (ref k, ref v)) in m {
                        s.emit_map_elt_key(i+1, |s| s.emit_str(k))?;
                        s.emit_map_elt_val(i+1, |s| v.encode(s))?;
                    }
                    Ok(())
                })
            })?;
            s.emit_seq_elt(1, |s| self.2.encode(s))?;
            s.emit_seq_elt(2, |s| self.3.encode(s))?;
            Ok(())
        })?;
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use rustc_serialize::json::{self, Json};

    use chat::message::{self, Call, Meta, Args, Kwargs, Auth, AuthData};
    use super::ValidationError as V;

    #[test]
    fn decode_message_errors() {
        macro_rules! err {
            ($a:expr, $b:expr) => {
                assert_eq!(message::decode_message($a).err().unwrap(), $b);
            }
        }
        err!("", V::ArrayExpected);
        err!("[invalid json", V::ArrayExpected);
        err!("{}", V::ArrayExpected);
        err!("[]", V::InvalidLength);
        err!("[1, 2, 3, 4, 5]", V::InvalidLength);
        err!("[1, 2, 3, 4]", V::ObjectExpected);
        err!("[null, null, null, 4]", V::ObjectExpected);
        err!("[1, 2, 3, {}]", V::ArrayExpected);
        err!("[1, 2, [], {}]", V::ObjectExpected);
        err!("[1, {}, [], {}]", V::InvalidRequestId);
        err!("[1, {\"request_id\": null}, [], {}]", V::InvalidRequestId);
        err!("[1, {\"request_id\": []}, [], {}]", V::InvalidRequestId);
        err!("[1, {\"request_id\": {}}, [], {}]", V::InvalidRequestId);
        err!("[1, {\"request_id\": \"\"}, [], {}]", V::InvalidRequestId);
        err!("[1, {\"request_id\": 123}, [], {}]", V::InvalidMethod);
        err!("[null, {\"request_id\": 123}, [], {}]", V::InvalidMethod);
        err!("[[], {\"request_id\": 123}, [], {}]", V::InvalidMethod);
        err!("[{}, {\"request_id\": 123}, [], {}]", V::InvalidMethod);
        err!("[\"bad/method\", {\"request_id\": 123}, [], {}]",
            V::InvalidMethod);
        err!("[\"very bad method\", {\"request_id\": 123}, [], {}]",
            V::InvalidMethod);
        err!("[\"tangle.auth\", {\"request_id\": 123}, [], {}]",
            V::InvalidMethod);
        err!("[\"   bad.method   \", {\"request_id\": 123}, [], {}]",
            V::InvalidMethod);
    }

    #[test]
    fn decode_message() {
        let res = message::decode_message(r#"
            ["some.method", {"request_id": "123"}, ["Hello"], {"world!": "!"}]
            "#).unwrap();
        let (method, meta, args, kwargs) = res;
        assert_eq!(method, "some.method".to_string());
        match meta.get("request_id".into()).unwrap() {
            &Json::String(ref s) => assert_eq!(s, &"123".to_string()),
            _ => unreachable!(),
        }
        assert_eq!(args.len(), 1);
        match kwargs.get("world!".into()).unwrap() {
            &Json::String(ref s) => assert_eq!(s, &"!".to_string()),
            _ => unreachable!(),
        }
    }

    #[test]
    fn encode_auth() {
        let res = json::encode(&Auth(&"conn:1".to_string(), &AuthData {
            http_cookie: None, http_authorization: None,
            url_querystring: "".to_string(),
        })).unwrap();
        assert_eq!(res, concat!(
            r#"[{"connection_id":"conn:1"},[],{"#,
            r#""http_cookie":null,"http_authorization":null,"#,
            r#""url_querystring":""}]"#));

        let kw = AuthData {
            http_cookie: Some("auth=ok".to_string()),
            http_authorization: None,
            url_querystring: "".to_string(),
        };

        let res = json::encode(&Auth(&"conn:2".to_string(), &kw)).unwrap();
        assert_eq!(res, concat!(
            r#"[{"connection_id":"conn:2"},"#,
            r#"[],{"http_cookie":"auth=ok","#,
            r#""http_authorization":null,"url_querystring":""}]"#));
    }

    #[test]
    fn encode_call() {
        let mut meta = Meta::new();
        let mut args = Args::new();
        let mut kw = Kwargs::new();
        let cid = "123".to_string();

        let res = json::encode(&Call(&meta, &cid, &args, &kw)).unwrap();
        assert_eq!(res, "[{\"connection_id\":\"123\"},[],{}]");

        meta.insert("request_id".into(), Json::String("123".into()));
        args.push(Json::String("Hello".into()));
        args.push(Json::String("World!".into()));
        kw.insert("room".into(), Json::U64(123));

        let res = json::encode(&Call(&meta, &cid, &args, &kw)).unwrap();
        assert_eq!(res, concat!(
            r#"[{"connection_id":"123","request_id":"123"},"#,
            r#"["Hello","World!"],"#,
            r#"{"room":123}]"#));

        meta.insert("connection_id".into(), Json::String("321".into()));
        let res = json::encode(&Call(&meta, &cid, &args, &kw)).unwrap();
        assert_eq!(res, concat!(
            r#"[{"connection_id":"123","request_id":"123"},"#,
            r#"["Hello","World!"],"#,
            r#"{"room":123}]"#));
    }

    #[test]
    fn get_active() {
        let mut meta = Meta::new();

        assert!(message::get_active(&meta).is_none());

        meta.insert("active".into(), Json::String("".into()));
        assert!(message::get_active(&meta).is_none());

        meta.insert("active".into(), Json::Boolean(true));
        assert!(message::get_active(&meta).is_some());
        assert_eq!(message::get_active(&meta).unwrap(), None);

        meta.insert("active".into(), Json::I64(123i64));
        assert!(message::get_active(&meta).is_none());

        meta.insert("active".into(), Json::F64(123f64));
        assert!(message::get_active(&meta).is_none());

        meta.insert("active".into(), Json::U64(123));
        assert_eq!(message::get_active(&meta).unwrap(), Some(123 as u64));

        if let Json::Object(meta) = Json::from_str("{\"active\": 123}")
            .unwrap()
        {
            assert!(message::get_active(&meta).is_some());
        }
    }
}
<commit_msg>chat inactivity: drop bool value support for 'active' flag<commit_after>/// Tangle request message.
///
/// ```javascript
/// ["chat.send_message", {"request_id": "123"}, ["text"], {}]
/// ```
use std::str;
use std::ascii::AsciiExt;
use std::collections::BTreeMap;

use rustc_serialize::json::{self, Json};
use rustc_serialize::{Encodable, Encoder};

pub type Meta = BTreeMap<String, Json>;
pub type Args = Vec<Json>;
pub type Kwargs = BTreeMap<String, Json>;

quick_error! {
    #[derive(Debug, PartialEq)]
    pub enum ValidationError {
        /// Invalid message length;
        InvalidLength {}
        /// Invalid method ("tangle." or contains ".");
        InvalidMethod {}
        /// request_id is missing or invalid in request_meta object;
        InvalidRequestId {}
        /// user_id is missing or invalid in request_meta object;
        InvalidUserId {}
        /// Array of args expected;
        ArrayExpected {}
        /// Meta/Kwargs object expected;
        ObjectExpected {}
    }
}

/// Decode Websocket json message into Meta & Message structs.
pub fn decode_message(s: &str)
    -> Result<(String, Meta, Args, Kwargs), ValidationError>
{
    use self::ValidationError::*;
    let valid_method = |m: &str| {
        !m.starts_with("tangle.") &&
        m.chars().all(|c| c.is_ascii() &&
            (c.is_alphanumeric() || c == '-' || c == '_' || c == '.' ))
    };
    match Json::from_str(s) {
        Ok(Json::Array(mut message)) => {
            use rustc_serialize::json::Json::*;

            if message.len() != 4 {
                return Err(InvalidLength)
            }
            let kwargs = match message.pop() {
                Some(Object(kwargs)) => kwargs,
                _ => return Err(ObjectExpected),
            };
            let args = match message.pop() {
                Some(Array(args)) => args,
                _ => return Err(ArrayExpected),
            };
            let meta = match message.pop() {
                Some(Object(meta)) => meta,
                _ => return Err(ObjectExpected),
            };
            match meta.get("request_id".into()) {
                Some(&Json::String(ref s)) if s.len() > 0 => {}
                Some(&Json::I64(_)) |
                    Some(&Json::U64(_)) |
                    Some(&Json::F64(_)) => {},
                _ => return Err(InvalidRequestId),
            };
            let method = match message.pop() {
                Some(Json::String(method)) => {
                    if !valid_method(&method) {
                        return Err(InvalidMethod);
                    }
                    method
                }
                _ => return Err(InvalidMethod),
            };
            Ok((method, meta, args, kwargs))
        }
        _ => Err(ArrayExpected),
    }
}

/// Returns true if Meta object contains 'active' key and
/// it either set to true or uint timeout (in seconds).
pub fn get_active(meta: &Meta) -> Option<u64>
{
    let duration = meta.get(&"active".to_string());
    match duration {
        Some(&Json::U64(v)) => Some(v),
        _ => None,
    }
}

#[derive(RustcEncodable)]
pub struct AuthData {
    pub http_cookie: Option<String>,
    pub http_authorization: Option<String>,
    pub url_querystring: String,
}

// Private tools

pub struct Auth<'a>(pub &'a String, pub &'a AuthData);

impl<'a> Encodable for Auth<'a> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_seq(3, |s| {
            s.emit_seq_elt(0, |s| {
                s.emit_map(1, |s| {
                    s.emit_map_elt_key(0, |s| s.emit_str("connection_id"))?;
                    s.emit_map_elt_val(0, |s| self.0.encode(s))?;
                    Ok(())
                })?;
                Ok(())
            })?;
            s.emit_seq_elt(1, |s| s.emit_seq(0, |_| Ok(())))?;
            s.emit_seq_elt(2, |s| self.1.encode(s))?;
            Ok(())
        })?;
        Ok(())
    }
}

pub struct Call<'a>(pub &'a Meta, pub &'a String, pub &'a Args, pub &'a Kwargs);

impl<'a> Encodable for Call<'a> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_seq(3, |s| {
            s.emit_seq_elt(0, |s| {
                let n = match self.0.get("connection_id") {
                    Some(_) => self.0.len(),
                    None => self.0.len() + 1,
                };
                s.emit_map(n, |s| {
                    s.emit_map_elt_key(0, |s| s.emit_str("connection_id"))?;
                    s.emit_map_elt_val(0, |s| self.1.encode(s))?;
                    let m = self.0.iter()
                        .filter(|&(&ref k, _)| k != "connection_id")
                        .enumerate();
                    for (i, (ref k, ref v)) in m {
                        s.emit_map_elt_key(i+1, |s| s.emit_str(k))?;
                        s.emit_map_elt_val(i+1, |s| v.encode(s))?;
                    }
                    Ok(())
                })
            })?;
            s.emit_seq_elt(1, |s| self.2.encode(s))?;
            s.emit_seq_elt(2, |s| self.3.encode(s))?;
            Ok(())
        })?;
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use rustc_serialize::json::{self, Json};

    use chat::message::{self, Call, Meta, Args, Kwargs, Auth, AuthData};
    use super::ValidationError as V;

    #[test]
    fn decode_message_errors() {
        macro_rules! err {
            ($a:expr, $b:expr) => {
                assert_eq!(message::decode_message($a).err().unwrap(), $b);
            }
        }
        err!("", V::ArrayExpected);
        err!("[invalid json", V::ArrayExpected);
        err!("{}", V::ArrayExpected);
        err!("[]", V::InvalidLength);
        err!("[1, 2, 3, 4, 5]", V::InvalidLength);
        err!("[1, 2, 3, 4]", V::ObjectExpected);
        err!("[null, null, null, 4]", V::ObjectExpected);
        err!("[1, 2, 3, {}]", V::ArrayExpected);
        err!("[1, 2, [], {}]", V::ObjectExpected);
        err!("[1, {}, [], {}]", V::InvalidRequestId);
        err!("[1, {\"request_id\": null}, [], {}]", V::InvalidRequestId);
        err!("[1, {\"request_id\": []}, [], {}]", V::InvalidRequestId);
        err!("[1, {\"request_id\": {}}, [], {}]", V::InvalidRequestId);
        err!("[1, {\"request_id\": \"\"}, [], {}]", V::InvalidRequestId);
        err!("[1, {\"request_id\": 123}, [], {}]", V::InvalidMethod);
        err!("[null, {\"request_id\": 123}, [], {}]", V::InvalidMethod);
        err!("[[], {\"request_id\": 123}, [], {}]", V::InvalidMethod);
        err!("[{}, {\"request_id\": 123}, [], {}]", V::InvalidMethod);
        err!("[\"bad/method\", {\"request_id\": 123}, [], {}]",
            V::InvalidMethod);
        err!("[\"very bad method\", {\"request_id\": 123}, [], {}]",
            V::InvalidMethod);
        err!("[\"tangle.auth\", {\"request_id\": 123}, [], {}]",
            V::InvalidMethod);
        err!("[\"   bad.method   \", {\"request_id\": 123}, [], {}]",
            V::InvalidMethod);
    }

    #[test]
    fn decode_message() {
        let res = message::decode_message(r#"
            ["some.method", {"request_id": "123"}, ["Hello"], {"world!": "!"}]
            "#).unwrap();
        let (method, meta, args, kwargs) = res;
        assert_eq!(method, "some.method".to_string());
        match meta.get("request_id".into()).unwrap() {
            &Json::String(ref s) => assert_eq!(s, &"123".to_string()),
            _ => unreachable!(),
        }
        assert_eq!(args.len(), 1);
        match kwargs.get("world!".into()).unwrap() {
            &Json::String(ref s) => assert_eq!(s, &"!".to_string()),
            _ => unreachable!(),
        }
    }

    #[test]
    fn encode_auth() {
        let res = json::encode(&Auth(&"conn:1".to_string(), &AuthData {
            http_cookie: None, http_authorization: None,
            url_querystring: "".to_string(),
        })).unwrap();
        assert_eq!(res, concat!(
            r#"[{"connection_id":"conn:1"},[],{"#,
            r#""http_cookie":null,"http_authorization":null,"#,
            r#""url_querystring":""}]"#));

        let kw = AuthData {
            http_cookie: Some("auth=ok".to_string()),
            http_authorization: None,
            url_querystring: "".to_string(),
        };

        let res = json::encode(&Auth(&"conn:2".to_string(), &kw)).unwrap();
        assert_eq!(res, concat!(
            r#"[{"connection_id":"conn:2"},"#,
            r#"[],{"http_cookie":"auth=ok","#,
            r#""http_authorization":null,"url_querystring":""}]"#));
    }

    #[test]
    fn encode_call() {
        let mut meta = Meta::new();
        let mut args = Args::new();
        let mut kw = Kwargs::new();
        let cid = "123".to_string();

        let res = json::encode(&Call(&meta, &cid, &args, &kw)).unwrap();
        assert_eq!(res, "[{\"connection_id\":\"123\"},[],{}]");

        meta.insert("request_id".into(), Json::String("123".into()));
        args.push(Json::String("Hello".into()));
        args.push(Json::String("World!".into()));
        kw.insert("room".into(), Json::U64(123));

        let res = json::encode(&Call(&meta, &cid, &args, &kw)).unwrap();
        assert_eq!(res, concat!(
            r#"[{"connection_id":"123","request_id":"123"},"#,
            r#"["Hello","World!"],"#,
            r#"{"room":123}]"#));

        meta.insert("connection_id".into(), Json::String("321".into()));
        let res = json::encode(&Call(&meta, &cid, &args, &kw)).unwrap();
        assert_eq!(res, concat!(
            r#"[{"connection_id":"123","request_id":"123"},"#,
            r#"["Hello","World!"],"#,
            r#"{"room":123}]"#));
    }

    #[test]
    fn get_active() {
        let mut meta = Meta::new();

        assert!(message::get_active(&meta).is_none());

        meta.insert("active".into(), Json::String("".into()));
        assert!(message::get_active(&meta).is_none());

        meta.insert("active".into(), Json::Boolean(true));
        assert!(message::get_active(&meta).is_none());

        meta.insert("active".into(), Json::I64(123i64));
        assert!(message::get_active(&meta).is_none());

        meta.insert("active".into(), Json::F64(123f64));
        assert!(message::get_active(&meta).is_none());

        meta.insert("active".into(), Json::U64(123));
        assert_eq!(message::get_active(&meta).unwrap(), 123u64);

        if let Json::Object(meta) = Json::from_str("{\"active\": 123}")
            .unwrap()
        {
            assert!(message::get_active(&meta).is_some());
        }
    }
}
<|endoftext|>


<commit_before>use neon::prelude::*;
use std::sync::{Mutex, MutexGuard};
use stencila::{
    once_cell::sync::{Lazy, OnceCell},
    pubsub, serde_json,
};

use crate::prelude::from_json;

pub struct JsSubscription {
    topic: String,
    subscriber: Root<JsFunction>,
}

static SUBSCRIPTIONS: Lazy<Mutex<Vec<JsSubscription>>> = Lazy::new(|| Mutex::new(Vec::new()));

/// The Neon event queue to which published events will be sent
static QUEUE: OnceCell<EventQueue> = OnceCell::new();

/// Obtain the subscriptions store
pub fn obtain(cx: &mut FunctionContext) -> NeonResult<MutexGuard<'static, Vec<JsSubscription>>> {
    match SUBSCRIPTIONS.try_lock() {
        Ok(guard) => Ok(guard),
        Err(error) => cx.throw_error(format!(
            "When attempting to obtain subscriptions: {}",
            error.to_string()
        )),
    }
}

/// Subscribe to a topic
pub fn subscribe(mut cx: FunctionContext) -> JsResult<JsUndefined> {
    let topic = cx.argument::<JsString>(0)?.value(&mut cx);
    let subscriber = cx.argument::<JsFunction>(1)?.root(&mut cx);

    let queue = cx.queue();
    if QUEUE.set(queue).is_err() {
        // Ignore because it just means queue was already set
    }

    let mut subscriptions = obtain(&mut cx)?;
    subscriptions.push(JsSubscription { topic, subscriber });

    Ok(cx.undefined())
}

/// Unsubscribe from a topic
pub fn unsubscribe(mut cx: FunctionContext) -> JsResult<JsUndefined> {
    let topic = cx.argument::<JsString>(0)?.value(&mut cx);

    let mut subscriptions = obtain(&mut cx)?;
    subscriptions.retain(|subscription| subscription.topic != topic);

    Ok(cx.undefined())
}

/// Publish data for a topic
pub fn publish(mut cx: FunctionContext) -> JsResult<JsUndefined> {
    let topic = cx.argument::<JsString>(0)?.value(&mut cx);
    let json = cx.argument::<JsString>(1)?.value(&mut cx);

    bridging_subscriber(topic, from_json::<serde_json::Value>(&mut cx, &json)?);

    Ok(cx.undefined())
}

/// A subscriber that acts as a bridge between Rust events and Javascript events
/// (i.e. takes a Rust event and turns it into a Javascript one)
///
/// This function is called by Rust for ALL topics and it passes on events to
/// Node.js subscribers that have subscribed to the particular topic.
pub fn bridging_subscriber(topic: String, data: serde_json::Value) {
    // If the queue is not set then it means that there are
    // no subscribers and so no need to do anything
    if let Some(queue) = QUEUE.get() {
        queue.send(move |mut cx| {
            let subscriptions = &*SUBSCRIPTIONS
                .lock()
                .expect("Unable to obtain subscriptions lock");

            for JsSubscription {
                topic: sub_topic,
                subscriber,
            } in subscriptions
            {
                if sub_topic == "*" || topic.starts_with(sub_topic) {
                    let callback = subscriber.to_inner(&mut cx);
                    let this = cx.undefined();
                    let json = serde_json::to_string(&data).expect("Unable to convert to JSON");
                    let args = vec![cx.string(&topic), cx.string(json)];
                    callback.call(&mut cx, this, args)?;
                }
            }
            Ok(())
        });
    }
}

/// Initialize the pubsub module by registering the `bridging_subscriber`
/// as a subscriber to all topics.
pub fn init(mut cx: FunctionContext) -> JsResult<JsUndefined> {
    if let Err(error) = pubsub::subscribe("*", bridging_subscriber) {
        return cx.throw_error(format!(
            "While attempting to initialize pubsub: {}",
            error.to_string()
        ));
    }
    Ok(cx.undefined())
}
<commit_msg>docs(Node.js): Add docs for pubsub module<commit_after>use crate::prelude::from_json;
use neon::prelude::*;
use std::sync::{Mutex, MutexGuard};
use stencila::{
    once_cell::sync::{Lazy, OnceCell},
    pubsub, serde_json,
};

/// The Neon event queue to which published events will be sent
static QUEUE: OnceCell<EventQueue> = OnceCell::new();

/// A JavaScript subscription
#[derive(Debug)]
pub struct JsSubscription {
    /// The topic that is subscribed to
    topic: String,

    /// The subscriber function
    subscriber: Root<JsFunction>,
}

/// A list of JavaScript subscriptions
static SUBSCRIPTIONS: Lazy<Mutex<Vec<JsSubscription>>> = Lazy::new(|| Mutex::new(Vec::new()));

/// Obtain the subscriptions store
pub fn obtain(cx: &mut FunctionContext) -> NeonResult<MutexGuard<'static, Vec<JsSubscription>>> {
    match SUBSCRIPTIONS.try_lock() {
        Ok(guard) => Ok(guard),
        Err(error) => cx.throw_error(format!(
            "When attempting to obtain subscriptions: {}",
            error.to_string()
        )),
    }
}

/// Subscribe to a topic
pub fn subscribe(mut cx: FunctionContext) -> JsResult<JsUndefined> {
    let topic = cx.argument::<JsString>(0)?.value(&mut cx);
    let subscriber = cx.argument::<JsFunction>(1)?.root(&mut cx);

    let queue = cx.queue();
    if QUEUE.set(queue).is_err() {
        // Ignore because it just means queue was already set
    }

    let mut subscriptions = obtain(&mut cx)?;
    subscriptions.push(JsSubscription { topic, subscriber });

    Ok(cx.undefined())
}

/// Unsubscribe from a topic
pub fn unsubscribe(mut cx: FunctionContext) -> JsResult<JsUndefined> {
    let topic = cx.argument::<JsString>(0)?.value(&mut cx);

    let mut subscriptions = obtain(&mut cx)?;
    subscriptions.retain(|subscription| subscription.topic != topic);

    Ok(cx.undefined())
}

/// Publish data for a topic
pub fn publish(mut cx: FunctionContext) -> JsResult<JsUndefined> {
    let topic = cx.argument::<JsString>(0)?.value(&mut cx);
    let json = cx.argument::<JsString>(1)?.value(&mut cx);

    bridging_subscriber(topic, from_json::<serde_json::Value>(&mut cx, &json)?);

    Ok(cx.undefined())
}

/// A subscriber that acts as a bridge between Rust events and Javascript events
/// (i.e. takes a Rust event and turns it into a Javascript one)
///
/// This function is called by Rust for ALL topics and it passes on events to
/// Node.js subscribers that have subscribed to the particular topic.
pub fn bridging_subscriber(topic: String, data: serde_json::Value) {
    // If the queue is not set then it means that there are
    // no subscribers and so no need to do anything
    if let Some(queue) = QUEUE.get() {
        queue.send(move |mut cx| {
            let subscriptions = &*SUBSCRIPTIONS
                .lock()
                .expect("Unable to obtain subscriptions lock");

            for JsSubscription {
                topic: sub_topic,
                subscriber,
            } in subscriptions
            {
                if sub_topic == "*" || topic.starts_with(sub_topic) {
                    let callback = subscriber.to_inner(&mut cx);
                    let this = cx.undefined();
                    let json = serde_json::to_string(&data).expect("Unable to convert to JSON");
                    let args = vec![cx.string(&topic), cx.string(json)];
                    callback.call(&mut cx, this, args)?;
                }
            }
            Ok(())
        });
    }
}

/// Initialize the pubsub module by registering the `bridging_subscriber`
/// as a subscriber to all topics.
pub fn init(mut cx: FunctionContext) -> JsResult<JsUndefined> {
    if let Err(error) = pubsub::subscribe("*", bridging_subscriber) {
        return cx.throw_error(format!(
            "While attempting to initialize pubsub: {}",
            error.to_string()
        ));
    }
    Ok(cx.undefined())
}
<|endoftext|>


<commit_before>use std::fmt;

use super::lazy_buffer::LazyBuffer;

/// An iterator to iterate through all the `k`-length combinations in an iterator.
///
/// See [`.combinations()`](../trait.Itertools.html#method.combinations) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Combinations<I: Iterator> {
    indices: Vec<usize>,
    pool: LazyBuffer<I>,
    first: bool,
}

impl<I> Clone for Combinations<I>
    where I: Clone + Iterator,
          I::Item: Clone,
{
    clone_fields!(indices, pool, first);
}

impl<I> fmt::Debug for Combinations<I>
    where I: Iterator + fmt::Debug,
          I::Item: fmt::Debug,
{
    debug_fmt_fields!(Combinations, indices, pool, first);
}

/// Create a new `Combinations` from a clonable iterator.
pub fn combinations<I>(iter: I, k: usize) -> Combinations<I>
    where I: Iterator
{
    let mut pool: LazyBuffer<I> = LazyBuffer::new(iter);

    for _ in 0..k {
        if !pool.get_next() {
            break;
        }
    }

    Combinations {
        indices: (0..k).collect(),
        pool,
        first: true,
    }
}

impl<I> Iterator for Combinations<I>
    where I: Iterator,
          I::Item: Clone
{
    type Item = Vec<I::Item>;
    fn next(&mut self) -> Option<Self::Item> {
        let mut pool_len = self.pool.len();

        if self.first {
            if self.pool.is_done() {
                return None;
            }
            self.first = false;
        } else if self.indices.len() == 0 {
            return None;
        } else {
            // Scan from the end, looking for an index to increment
            let mut i: usize = self.indices.len() - 1;

            // Check if we need to consume more from the iterator
            if self.indices[i] == pool_len - 1 && !self.pool.is_done() {
                if self.pool.get_next() {
                    pool_len += 1;
                }
            }

            while self.indices[i] == i + pool_len - self.indices.len() {
                if i > 0 {
                    i -= 1;
                } else {
                    // Reached the last combination
                    return None;
                }
            }

            // Increment index, and reset the ones to its right
            self.indices[i] += 1;
            for j in i+1..self.indices.len() {
                self.indices[j] = self.indices[j - 1] + 1;
            }
        }

        // Create result vector based on the indices
        Some(self.indices.iter().map(|i| self.pool[*i].clone()).collect())
    }
}
<commit_msg>Avoid redundant bookkeeping in `pool_len`<commit_after>use std::fmt;

use super::lazy_buffer::LazyBuffer;

/// An iterator to iterate through all the `k`-length combinations in an iterator.
///
/// See [`.combinations()`](../trait.Itertools.html#method.combinations) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Combinations<I: Iterator> {
    indices: Vec<usize>,
    pool: LazyBuffer<I>,
    first: bool,
}

impl<I> Clone for Combinations<I>
    where I: Clone + Iterator,
          I::Item: Clone,
{
    clone_fields!(indices, pool, first);
}

impl<I> fmt::Debug for Combinations<I>
    where I: Iterator + fmt::Debug,
          I::Item: fmt::Debug,
{
    debug_fmt_fields!(Combinations, indices, pool, first);
}

/// Create a new `Combinations` from a clonable iterator.
pub fn combinations<I>(iter: I, k: usize) -> Combinations<I>
    where I: Iterator
{
    let mut pool: LazyBuffer<I> = LazyBuffer::new(iter);

    for _ in 0..k {
        if !pool.get_next() {
            break;
        }
    }

    Combinations {
        indices: (0..k).collect(),
        pool,
        first: true,
    }
}

impl<I> Iterator for Combinations<I>
    where I: Iterator,
          I::Item: Clone
{
    type Item = Vec<I::Item>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.first {
            if self.pool.is_done() {
                return None;
            }
            self.first = false;
        } else if self.indices.len() == 0 {
            return None;
        } else {
            // Scan from the end, looking for an index to increment
            let mut i: usize = self.indices.len() - 1;

            // Check if we need to consume more from the iterator
            if self.indices[i] == self.pool.len() - 1 && !self.pool.is_done() {
                self.pool.get_next(); // may change pool size
            }

            while self.indices[i] == i + self.pool.len() - self.indices.len() {
                if i > 0 {
                    i -= 1;
                } else {
                    // Reached the last combination
                    return None;
                }
            }

            // Increment index, and reset the ones to its right
            self.indices[i] += 1;
            for j in i+1..self.indices.len() {
                self.indices[j] = self.indices[j - 1] + 1;
            }
        }

        // Create result vector based on the indices
        Some(self.indices.iter().map(|i| self.pool[*i].clone()).collect())
    }
}
<|endoftext|>