<commit_before>use std::collections::HashMap;
use std::{thread, time};
use std::cell::{RefCell, RefMut};

use reqwest::{Response};

use errors::Error;
use client::MatrixClient;
use matrix_types::Event;

#[derive(Clone)]
pub struct RoomEvent<'a> {
    pub room_id: &'a str,
    pub raw_event: Event,
}

pub struct Bot <'a, 'b> {
    client: RefCell<&'b mut MatrixClient>,
    root_services: Vec<&'a str>,
    all_services: HashMap<&'a str, RefCell<Box<Node<'a>>>>,

    rooms: RefCell<Vec<String>>,
}

impl<'a, 'b> Bot<'a, 'b> {
    pub fn new(client: &'b mut MatrixClient) -> Self{
        Bot {
            client: RefCell::new(client),
            root_services: Vec::new(),
            all_services: HashMap::new(),
            rooms: RefCell::new(Vec::new()),
        }
    }

    pub fn join(&self, room_id: &str) -> Result<Response, Error>{
        self.rooms.borrow_mut().push(room_id.clone().to_string());

        self.client.borrow().join(room_id)
    }

    pub fn join_public(&self, room_id: &str) -> Result<Response, Error>{
        let pub_room = self.client.borrow().get_public_room_id(room_id);

        match pub_room {
            Some(id) => self.join(&id),
            None => Err("Could not join invalid room.".into()),
        }
    }

    pub fn say(&self, room_id: &str, message: &str) -> Result<Response, Error> {
        self.client.borrow_mut().send_msg(room_id, message)
    }

    pub fn reply(&self, event: &RoomEvent, message: &str) -> Result<Response, Error> {
        self.say(event.room_id, message)
    }

    pub fn kick(&self, room_id: &str, user_id: &str, reason: Option<&str>) {
        self.client.borrow().kick(room_id, user_id, reason);
    }

    /*
    pub fn action(&self, room_id: &str, action: &str) {
    }

    pub fn set_name(&self, name: &str) {
    }
    */

    pub fn register_service(&mut self,
                            name: &'a str,
                            parent: Option<&'a str>,
                            mut service: Box<Node<'a>>) -> Option<&'a str> {
        match parent {
            Some(p) => {
                self.all_services.get_mut(p).expect("Invalid parent node")
                    .borrow_mut().register_child(name)
            },
            None => self.root_services.push(name),
        };

        service.on_load();

        self.all_services.insert(name, RefCell::new(service));

        Some(name)
    }

    pub fn get_service(&self, name: &str) -> RefMut<Box<Node<'a>>> {
        self.all_services.get(name).unwrap().borrow_mut()
    }

    pub fn propagate_event(&self, event: &RoomEvent) {
        for service in &self.root_services {
            self.all_services.get(service).unwrap()
                .borrow_mut().handle(self, event.clone());
        }
    }

    pub fn run(&mut self, initial_rooms: &Vec<&str>) {
        for room in initial_rooms {
            if let Some(rid) = self.client.borrow().get_public_room_id(room) {
                println!("Joining {} id: {}", &room, &rid);
                self.join(&rid);
            } else {
                println!("Could not join room {}", &room);
            }
        }

        let mut next_batch: String = self.client.borrow().sync(None).unwrap().next_batch;

        let delay = time::Duration::from_millis(500);

        loop {
            // TODO: NLL May let this extra temp variable die
            let sync = self.client.borrow().sync(Some(&next_batch));

            match sync {
                Ok(sync_data) => {
                    let rooms = self.rooms.borrow().clone();
                    for room_id in rooms.iter() {
                        if let Some(room) = sync_data.rooms.join.get(room_id) {
                            for raw_event in &room.timeline.events {
                                self.propagate_event(
                                    &RoomEvent{room_id, raw_event: raw_event.clone()}
                                );
                            }
                        }
                    }

                    next_batch = sync_data.next_batch;
                },
                Err(e) => {
                    println!("Error: {:?}", e);
                }
            }

            thread::sleep(delay);
        }
    }
}

pub trait Node<'a> {
    fn children(&self) -> Option<&Vec<&'a str>> {
        None
    }

    fn register_child(&mut self, name: &'a str) {
    }

    fn propagate_event(&self, bot: &Bot, event: &RoomEvent) {
        if let Some(children) = self.children() {
            for child in children {
                bot.get_service(child).handle(bot, event.clone());
            }
        }
    }

    fn handle(&mut self, bot: &Bot, event: RoomEvent) {
        self.propagate_event(bot, &event);
    }

    fn on_load(&mut self) { }

    fn on_exit(&self) { }
}

/*
if let Ok(x) = serde_json::to_string_pretty(&res.rooms.join) {
    println!("{}", x);
} */
<commit_msg>Fix bug where bot could join room multiple times<commit_after>use std::collections::HashMap;
use std::{thread, time};
use std::cell::{RefCell, RefMut};

use reqwest::{Response};

use errors::Error;
use client::MatrixClient;
use matrix_types::Event;

#[derive(Clone)]
pub struct RoomEvent<'a> {
    pub room_id: &'a str,
    pub raw_event: Event,
}

pub struct Bot <'a, 'b> {
    client: RefCell<&'b mut MatrixClient>,
    root_services: Vec<&'a str>,
    all_services: HashMap<&'a str, RefCell<Box<Node<'a>>>>,

    rooms: RefCell<Vec<String>>,
}

impl<'a, 'b> Bot<'a, 'b> {
    pub fn new(client: &'b mut MatrixClient) -> Self{
        Bot {
            client: RefCell::new(client),
            root_services: Vec::new(),
            all_services: HashMap::new(),
            rooms: RefCell::new(Vec::new()),
        }
    }

    pub fn join(&self, room_id: &str) -> Result<Response, Error>{
        // Make sure that the bot isn't already in the room to be joined
        for room in self.rooms.borrow().iter() {
            if room_id == room {
                return Err("Already in room".into());
            }
        }

        self.rooms.borrow_mut().push(room_id.clone().to_string());

        self.client.borrow().join(room_id)
    }

    pub fn join_public(&self, room_id: &str) -> Result<Response, Error>{
        let pub_room = self.client.borrow().get_public_room_id(room_id);

        match pub_room {
            Some(id) => self.join(&id),
            None => Err("Could not join invalid room.".into()),
        }
    }

    pub fn say(&self, room_id: &str, message: &str) -> Result<Response, Error> {
        self.client.borrow_mut().send_msg(room_id, message)
    }

    pub fn reply(&self, event: &RoomEvent, message: &str) -> Result<Response, Error> {
        self.say(event.room_id, message)
    }

    pub fn kick(&self, room_id: &str, user_id: &str, reason: Option<&str>) {
        self.client.borrow().kick(room_id, user_id, reason);
    }

    /*
    pub fn action(&self, room_id: &str, action: &str) {
    }

    pub fn set_name(&self, name: &str) {
    }
    */

    pub fn register_service(&mut self,
                            name: &'a str,
                            parent: Option<&'a str>,
                            mut service: Box<Node<'a>>) -> Option<&'a str> {
        match parent {
            Some(p) => {
                self.all_services.get_mut(p).expect("Invalid parent node")
                    .borrow_mut().register_child(name)
            },
            None => self.root_services.push(name),
        };

        service.on_load();

        self.all_services.insert(name, RefCell::new(service));

        Some(name)
    }

    pub fn get_service(&self, name: &str) -> RefMut<Box<Node<'a>>> {
        self.all_services.get(name).unwrap().borrow_mut()
    }

    pub fn propagate_event(&self, event: &RoomEvent) {
        for service in &self.root_services {
            self.all_services.get(service).unwrap()
                .borrow_mut().handle(self, event.clone());
        }
    }

    pub fn run(&mut self, initial_rooms: &Vec<&str>) {
        for room in initial_rooms {
            if let Some(rid) = self.client.borrow().get_public_room_id(room) {
                println!("Joining {} id: {}", &room, &rid);
                self.join(&rid);
            } else {
                println!("Could not join room {}", &room);
            }
        }

        let mut next_batch: String = self.client.borrow().sync(None).unwrap().next_batch;

        let delay = time::Duration::from_millis(500);

        loop {
            // TODO: NLL May let this extra temp variable die
            let sync = self.client.borrow().sync(Some(&next_batch));

            match sync {
                Ok(sync_data) => {
                    let rooms = self.rooms.borrow().clone();
                    for room_id in rooms.iter() {
                        if let Some(room) = sync_data.rooms.join.get(room_id) {
                            for raw_event in &room.timeline.events {
                                self.propagate_event(
                                    &RoomEvent{room_id, raw_event: raw_event.clone()}
                                );
                            }
                        }
                    }

                    next_batch = sync_data.next_batch;
                },
                Err(e) => {
                    println!("Error: {:?}", e);
                }
            }

            thread::sleep(delay);
        }
    }
}

pub trait Node<'a> {
    fn children(&self) -> Option<&Vec<&'a str>> {
        None
    }

    fn register_child(&mut self, name: &'a str) {
    }

    fn propagate_event(&self, bot: &Bot, event: &RoomEvent) {
        if let Some(children) = self.children() {
            for child in children {
                bot.get_service(child).handle(bot, event.clone());
            }
        }
    }

    fn handle(&mut self, bot: &Bot, event: RoomEvent) {
        self.propagate_event(bot, &event);
    }

    fn on_load(&mut self) { }

    fn on_exit(&self) { }
}

/*
if let Ok(x) = serde_json::to_string_pretty(&res.rooms.join) {
    println!("{}", x);
} */
<|endoftext|>


<commit_before>//! Simple graphviz dot file format output

use std::fmt::{self, Display, Write};
use {
    Graph,
    EdgeType,
    GraphMap,
};
use super::graph::IndexType;
use graphmap::NodeTrait;
use std::collections::HashMap;

/// `Dot` implements output to graphviz .dot format for a graph.
///
/// Formatting and options are rather simple, this is mostly intended
/// for debugging. Exact output may change.
pub struct Dot<'a, G: 'a> {
    graph: &'a G,
    config: &'a [Config],
}

static TYPE: [&'static str; 2] = ["graph", "digraph"];
static EDGE: [&'static str; 2] = ["--", "->"];
static INDENT: &'static str = "    ";

impl<'a, G> Dot<'a, G> {
    pub fn new(graph: &'a G) -> Self {
        Self::with_config(graph, &[])
    }

    pub fn with_config(graph: &'a G, config: &'a [Config]) -> Self {
        Dot {
            graph: graph,
            config: config,
        }
    }
}

/// `Dot` configuration.
///
/// This enum does not have an exhaustive definition (will be expanded)
#[derive(Debug, PartialEq, Eq)]
pub enum Config {
    NodeIndexLabel,
    EdgeIndexLabel,
    EdgeNoLabel,
    #[doc(hidden)]
    Other
}

impl<'a, N, E, Ty, Ix> Dot<'a, Graph<N, E, Ty, Ix>>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn graph_fmt<F, G>(&self, f: &mut fmt::Formatter,
                       mut node_fmt: F, mut edge_fmt: G) -> fmt::Result
        where F: FnMut(&N, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
              G: FnMut(&E, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
{
        let g = self.graph;
        try!(writeln!(f, "{} {{", TYPE[g.is_directed() as usize]));

        // output all labels
        for index in g.node_indices() {
            try!(write!(f, "{}{}", INDENT, index.index()));
            if self.config.contains(&Config::NodeIndexLabel) {
                try!(writeln!(f, ""));
            } else {
                try!(write!(f, " [label=\""));
                try!(node_fmt(&g[index], &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }

        }
        // output all edges
        for (i, edge) in g.raw_edges().iter().enumerate() {
            try!(write!(f, "{}{} {} {}",
                        INDENT,
                        edge.source().index(),
                        EDGE[g.is_directed() as usize],
                        edge.target().index()));
            if self.config.contains(&Config::EdgeNoLabel) {
                try!(writeln!(f, ""));
            } else if self.config.contains(&Config::EdgeIndexLabel) {
                try!(writeln!(f, " [label=\"{}\"]", i));
            } else {
                try!(write!(f, " [label=\""));
                try!(edge_fmt(&edge.weight, &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }
        }

        try!(writeln!(f, "}}"));
        Ok(())
    }
}

impl<'a, N, E, Ty, Ix> fmt::Display for Dot<'a, Graph<N, E, Ty, Ix>>
    where N: fmt::Display,
          E: fmt::Display,
          Ty: EdgeType,
          Ix: IndexType,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graph_fmt(f, |n, cb| cb(n), |e, cb| cb(e))
    }
}

impl<'a, N, E, Ty, Ix> fmt::Debug for Dot<'a, Graph<N, E, Ty, Ix>>
    where N: fmt::Debug,
          E: fmt::Debug,
          Ty: EdgeType,
          Ix: IndexType,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graph_fmt(f,
                       |n, cb| cb(&format_args!("{:?}", n)),
                       |e, cb| cb(&format_args!("{:?}", e)))
    }
}

impl<'a, N, E> Dot<'a, GraphMap<N, E>>
    where N: NodeTrait,
{
    fn graphmap_fmt<F, G>(&self, f: &mut fmt::Formatter,
                          mut node_fmt: F, mut edge_fmt: G) -> fmt::Result
        where F: FnMut(&N, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
              G: FnMut(&E, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
    {
        let g = self.graph;
        try!(writeln!(f, "{} {{", TYPE[0]));

        let mut labels = HashMap::new();

        // output all labels
        for (i, node) in g.nodes().enumerate() {
            labels.insert(node, i);
            try!(write!(f, "{}{}", INDENT, i));
            if self.config.contains(&Config::NodeIndexLabel) {
                try!(writeln!(f, ""));
            } else {
                try!(write!(f, " [label=\""));
                try!(node_fmt(&node, &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }
        }
        // output all edges
        for (i, ((a, b), edge_weight)) in g.all_edges().enumerate() {
            try!(write!(f, "{}{} {} {}",
                        INDENT,
                        labels[&a],
                        EDGE[0],
                        labels[&b]));
            if self.config.contains(&Config::EdgeIndexLabel) {
                try!(writeln!(f, " [label=\"{}\"]", i));
            } else {
                try!(write!(f, " [label=\""));
                try!(edge_fmt(&edge_weight, &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }
        }

        try!(writeln!(f, "}}"));
        Ok(())
    }
}
impl<'a, N, E> fmt::Display for Dot<'a, GraphMap<N, E>>
    where N: fmt::Display + NodeTrait,
          E: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graphmap_fmt(f, |n, cb| cb(n), |e, cb| cb(e))
    }
}

impl<'a, N, E> fmt::Debug for Dot<'a, GraphMap<N, E>>
    where N: fmt::Debug + NodeTrait,
          E: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graphmap_fmt(f,
                          |n, cb| cb(&format_args!("{:?}", n)),
                          |e, cb| cb(&format_args!("{:?}", e)))
    }
}

/// For Graphviz, we only need to escape double quotes in labels
struct Escaper<W>(W);

impl<W> fmt::Write for Escaper<W>
    where W: fmt::Write
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        for c in s.chars() {
            try!(self.write_char(c));
        }
        Ok(())
    }

    fn write_char(&mut self, c: char) -> fmt::Result {
        match c {
            '"' => try!(self.0.write_char('\\')),
            _   => { }
        }
        self.0.write_char(c)
    }
}

/// Pass Display and Debug through simple escaping filter
struct Escaped<T>(T);

impl<T> fmt::Display for Escaped<T>
    where T: fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(&mut Escaper(f), "{}", &self.0)
    }
}

impl<T> fmt::Debug for Escaped<T>
    where T: fmt::Debug
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(&mut Escaper(f), "{:?}", &self.0)
    }
}
<commit_msg>Docs for dot<commit_after>//! Simple graphviz dot file format output

use std::fmt::{self, Display, Write};
use {
    Graph,
    EdgeType,
    GraphMap,
};
use super::graph::IndexType;
use graphmap::NodeTrait;
use std::collections::HashMap;

/// `Dot` implements output to graphviz .dot format for a graph.
///
/// Formatting and options are rather simple, this is mostly intended
/// for debugging. Exact output may change.
pub struct Dot<'a, G: 'a> {
    graph: &'a G,
    config: &'a [Config],
}

static TYPE: [&'static str; 2] = ["graph", "digraph"];
static EDGE: [&'static str; 2] = ["--", "->"];
static INDENT: &'static str = "    ";

impl<'a, G> Dot<'a, G> {
    /// Create a `Dot` formatting wrapper with default configuration.
    pub fn new(graph: &'a G) -> Self {
        Self::with_config(graph, &[])
    }

    /// Create a `Dot` formatting wrapper with custom configuration.
    pub fn with_config(graph: &'a G, config: &'a [Config]) -> Self {
        Dot {
            graph: graph,
            config: config,
        }
    }
}

/// `Dot` configuration.
///
/// This enum does not have an exhaustive definition (will be expanded)
#[derive(Debug, PartialEq, Eq)]
pub enum Config {
    /// Use indices for node labels.
    NodeIndexLabel,
    /// Use indices for edge labels.
    EdgeIndexLabel,
    /// Use no edge labels.
    EdgeNoLabel,
    #[doc(hidden)]
    Other
}

impl<'a, N, E, Ty, Ix> Dot<'a, Graph<N, E, Ty, Ix>>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn graph_fmt<F, G>(&self, f: &mut fmt::Formatter,
                       mut node_fmt: F, mut edge_fmt: G) -> fmt::Result
        where F: FnMut(&N, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
              G: FnMut(&E, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
{
        let g = self.graph;
        try!(writeln!(f, "{} {{", TYPE[g.is_directed() as usize]));

        // output all labels
        for index in g.node_indices() {
            try!(write!(f, "{}{}", INDENT, index.index()));
            if self.config.contains(&Config::NodeIndexLabel) {
                try!(writeln!(f, ""));
            } else {
                try!(write!(f, " [label=\""));
                try!(node_fmt(&g[index], &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }

        }
        // output all edges
        for (i, edge) in g.raw_edges().iter().enumerate() {
            try!(write!(f, "{}{} {} {}",
                        INDENT,
                        edge.source().index(),
                        EDGE[g.is_directed() as usize],
                        edge.target().index()));
            if self.config.contains(&Config::EdgeNoLabel) {
                try!(writeln!(f, ""));
            } else if self.config.contains(&Config::EdgeIndexLabel) {
                try!(writeln!(f, " [label=\"{}\"]", i));
            } else {
                try!(write!(f, " [label=\""));
                try!(edge_fmt(&edge.weight, &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }
        }

        try!(writeln!(f, "}}"));
        Ok(())
    }
}

impl<'a, N, E, Ty, Ix> fmt::Display for Dot<'a, Graph<N, E, Ty, Ix>>
    where N: fmt::Display,
          E: fmt::Display,
          Ty: EdgeType,
          Ix: IndexType,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graph_fmt(f, |n, cb| cb(n), |e, cb| cb(e))
    }
}

impl<'a, N, E, Ty, Ix> fmt::Debug for Dot<'a, Graph<N, E, Ty, Ix>>
    where N: fmt::Debug,
          E: fmt::Debug,
          Ty: EdgeType,
          Ix: IndexType,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graph_fmt(f,
                       |n, cb| cb(&format_args!("{:?}", n)),
                       |e, cb| cb(&format_args!("{:?}", e)))
    }
}

impl<'a, N, E> Dot<'a, GraphMap<N, E>>
    where N: NodeTrait,
{
    fn graphmap_fmt<F, G>(&self, f: &mut fmt::Formatter,
                          mut node_fmt: F, mut edge_fmt: G) -> fmt::Result
        where F: FnMut(&N, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
              G: FnMut(&E, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
    {
        let g = self.graph;
        try!(writeln!(f, "{} {{", TYPE[0]));

        let mut labels = HashMap::new();

        // output all labels
        for (i, node) in g.nodes().enumerate() {
            labels.insert(node, i);
            try!(write!(f, "{}{}", INDENT, i));
            if self.config.contains(&Config::NodeIndexLabel) {
                try!(writeln!(f, ""));
            } else {
                try!(write!(f, " [label=\""));
                try!(node_fmt(&node, &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }
        }
        // output all edges
        for (i, ((a, b), edge_weight)) in g.all_edges().enumerate() {
            try!(write!(f, "{}{} {} {}",
                        INDENT,
                        labels[&a],
                        EDGE[0],
                        labels[&b]));
            if self.config.contains(&Config::EdgeNoLabel) {
                try!(writeln!(f, ""));
            } else if self.config.contains(&Config::EdgeIndexLabel) {
                try!(writeln!(f, " [label=\"{}\"]", i));
            } else {
                try!(write!(f, " [label=\""));
                try!(edge_fmt(&edge_weight, &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }
        }

        try!(writeln!(f, "}}"));
        Ok(())
    }
}
impl<'a, N, E> fmt::Display for Dot<'a, GraphMap<N, E>>
    where N: fmt::Display + NodeTrait,
          E: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graphmap_fmt(f, |n, cb| cb(n), |e, cb| cb(e))
    }
}

impl<'a, N, E> fmt::Debug for Dot<'a, GraphMap<N, E>>
    where N: fmt::Debug + NodeTrait,
          E: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graphmap_fmt(f,
                          |n, cb| cb(&format_args!("{:?}", n)),
                          |e, cb| cb(&format_args!("{:?}", e)))
    }
}

/// For Graphviz, we only need to escape double quotes in labels
struct Escaper<W>(W);

impl<W> fmt::Write for Escaper<W>
    where W: fmt::Write
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        for c in s.chars() {
            try!(self.write_char(c));
        }
        Ok(())
    }

    fn write_char(&mut self, c: char) -> fmt::Result {
        match c {
            '"' => try!(self.0.write_char('\\')),
            _   => { }
        }
        self.0.write_char(c)
    }
}

/// Pass Display and Debug through simple escaping filter
struct Escaped<T>(T);

impl<T> fmt::Display for Escaped<T>
    where T: fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(&mut Escaper(f), "{}", &self.0)
    }
}

impl<T> fmt::Debug for Escaped<T>
    where T: fmt::Debug
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(&mut Escaper(f), "{:?}", &self.0)
    }
}
<|endoftext|>


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

// extern crate libc;
// use libc::{c_int, c_void, c_uchar, c_char};

use std::os::raw::{c_int, c_void, c_uchar, c_char};
use std::option::Option;

pub type uint8_t = u8;
pub type uint16_t = u16;
pub type uint32_t = u32;

pub enum rtlsdr_dev { }
type rtlsdr_dev_t = rtlsdr_dev;

pub struct Device {
    dev: *mut rtlsdr_dev_t,
}

#[derive(Copy, Clone)]
#[repr(u32)]
#[derive(Debug)]
pub enum rtlsdr_tuner {
    RTLSDR_TUNER_UNKNOWN = 0,
    RTLSDR_TUNER_E4000 = 1,
    RTLSDR_TUNER_FC0012 = 2,
    RTLSDR_TUNER_FC0013 = 3,
    RTLSDR_TUNER_FC2580 = 4,
    RTLSDR_TUNER_R820T = 5,
    RTLSDR_TUNER_R828D = 6,
}

#[derive(Copy, Clone)]
#[derive(Debug)]
pub enum Error {
    NoError,
    Io,
    InvalidParam,
    Access,
    NoDevice,
    NotFound,
    Busy,
    Timeout,
    Overflow,
    Pipe,
    Interrupted,
    NoMem,
    NotSupported,
    Other,
}

pub type rtlsdr_read_async_cb_t = Option<unsafe extern "C" fn(buf: *mut c_uchar,
                                                              len: uint32_t,
                                                              ctx: *mut c_void)>;

#[link(name = "rtlsdr")]
extern "C" {
    fn rtlsdr_get_device_count() -> uint32_t;
    fn rtlsdr_get_device_name(index: uint32_t) -> *const c_char;
    fn rtlsdr_get_device_usb_strings(index: uint32_t,
                                     manufact: *mut c_char,
                                     product: *mut c_char,
                                     serial: *mut c_char)
                                     -> c_int;
    fn rtlsdr_get_index_by_serial(serial: *const c_char) -> c_int;

    fn rtlsdr_open(dev: *mut *mut rtlsdr_dev_t, index: uint32_t) -> c_int;
    fn rtlsdr_close(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_xtal_freq(dev: *mut rtlsdr_dev_t,
                            rtl_freq: uint32_t,
                            tuner_freq: uint32_t)
                            -> c_int;
    fn rtlsdr_get_xtal_freq(dev: *mut rtlsdr_dev_t,
                            rtl_freq: *mut uint32_t,
                            tuner_freq: *mut uint32_t)
                            -> c_int;
    fn rtlsdr_get_usb_strings(dev: *mut rtlsdr_dev_t,
                              manufact: *mut c_char,
                              product: *mut c_char,
                              serial: *mut c_char)
                              -> c_int;
    fn rtlsdr_write_eeprom(dev: *mut rtlsdr_dev_t,
                           data: *mut uint8_t,
                           offset: uint8_t,
                           len: uint16_t)
                           -> c_int;
    fn rtlsdr_read_eeprom(dev: *mut rtlsdr_dev_t,
                          data: *mut uint8_t,
                          offset: uint8_t,
                          len: uint16_t)
                          -> c_int;
    fn rtlsdr_set_center_freq(dev: *mut rtlsdr_dev_t, freq: uint32_t) -> c_int;
    fn rtlsdr_get_center_freq(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_freq_correction(dev: *mut rtlsdr_dev_t, ppm: c_int) -> c_int;
    fn rtlsdr_get_freq_correction(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_get_tuner_type(dev: *mut rtlsdr_dev_t) -> rtlsdr_tuner;
    fn rtlsdr_get_tuner_gains(dev: *mut rtlsdr_dev_t, gains: *mut c_int) -> c_int;
    fn rtlsdr_set_tuner_gain(dev: *mut rtlsdr_dev_t, gain: c_int) -> c_int;
    fn rtlsdr_set_tuner_bandwidth(dev: *mut rtlsdr_dev_t, bw: uint32_t) -> c_int;
    fn rtlsdr_get_tuner_gain(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_tuner_if_gain(dev: *mut rtlsdr_dev_t, stage: c_int, gain: c_int) -> c_int;
    fn rtlsdr_set_tuner_gain_mode(dev: *mut rtlsdr_dev_t, manual: c_int) -> c_int;
    fn rtlsdr_set_sample_rate(dev: *mut rtlsdr_dev_t, rate: uint32_t) -> c_int;
    fn rtlsdr_get_sample_rate(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_testmode(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_set_agc_mode(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_set_direct_sampling(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_get_direct_sampling(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_offset_tuning(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_get_offset_tuning(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_reset_buffer(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_read_sync(dev: *mut rtlsdr_dev_t,
                        buf: *mut c_void,
                        len: c_int,
                        n_read: *mut c_int)
                        -> c_int;
    fn rtlsdr_wait_async(dev: *mut rtlsdr_dev_t,
                         cb: rtlsdr_read_async_cb_t,
                         ctx: *mut c_void)
                         -> c_int;
    fn rtlsdr_read_async(dev: *mut rtlsdr_dev_t,
                         cb: rtlsdr_read_async_cb_t,
                         ctx: *mut c_void,
                         buf_num: uint32_t,
                         buf_len: uint32_t)
                         -> c_int;
    fn rtlsdr_cancel_async(dev: *mut rtlsdr_dev_t) -> c_int;
}

fn get_err_msg(e: c_int) -> Error {
    use Error::*;
    match e {
        0 => NoError,
        -1 => Io,
        -2 => InvalidParam,
        -3 => Access,
        -4 => NoDevice,
        -5 => NotFound,
        -6 => Busy,
        -7 => Timeout,
        -8 => Overflow,
        -9 => Pipe,
        -10 => Interrupted,
        -11 => NoMem,
        -12 => NotSupported,
        _ => Other,
    }
}

// pub fn get_device_count() -> i32 {}
// pub fn get_device_name(index: ) ->  {}
// pub fn get_device_usb_strings( ) ->  i32 {}
// pub fn get_index_by_serial( ) ->  {}

pub fn open(index: i32) -> (Device, Error) {
    let mut d: *mut rtlsdr_dev_t = std::ptr::null_mut();
    unsafe {
        let e = rtlsdr_open(&mut d as *mut *mut rtlsdr_dev_t, index as uint32_t);
        return (Device {dev: d}, get_err_msg(e));
    }
}

impl Device {
    pub fn close(&self) -> Error {
        unsafe {
            return get_err_msg(rtlsdr_close(self.dev));
        }
    }
//     pub fn set_xtal_freq() -> Error {}
//     pub fn get_xtal_freq() -> Error {}
//     pub fn get_usb_strings() -> Error {}
//     pub fn write_eeprom() -> Error {}
//     pub fn read_eeprom() -> Error {}
//     pub fn set_center_freq() -> Error {}
//     pub fn get_center_freq() -> Error {}
//     pub fn set_freq_correction() -> Error {}
//     pub fn get_freq_correction() -> Error {}
//     pub fn get_tuner_type() -> rtlsdr_tuner {}
//     pub fn get_tuner_gains() -> Error {}
//     pub fn set_tuner_gain() -> Error {}
//     pub fn set_tuner_bandwidth() -> Error {}
//     pub fn get_tuner_gain() -> Error {}
//     pub fn set_tuner_if_gain() -> Error {}
//     pub fn set_tuner_gain_mode() -> Error {}
//     pub fn set_sample_rate() -> Error {}
//     pub fn get_sample_rate() -> Error {}
//     pub fn set_testmode() -> Error {}
//     pub fn set_agc_mode() -> Error {}
//     pub fn set_direct_sampling() -> Error {}
//     pub fn get_direct_sampling() -> Error {}
//     pub fn set_offset_tuning() -> Error {}
//     pub fn get_offset_tuning() -> Error {}
//     pub fn reset_buffer() -> Error {}
//     pub fn read_sync() -> Error {}
//     pub fn wait_async() -> Error {}
//     pub fn read_async() -> Error {}
//     pub fn cancel_async() -> Error {}
}

fn main() {
    println!("opening...");
    let (dev, err) = open(0);
    match err {
        Error::NoError => println!("open successful"),
        _ => return,
    }
    let e = dev.close();
    println!("dev close status: {:?}", e);
}
<commit_msg>better bar names<commit_after>
#![allow(dead_code,
         non_camel_case_types,
         non_upper_case_globals,
         non_snake_case)]

// extern crate libc;
// use libc::{c_int, c_void, c_uchar, c_char};

use std::os::raw::{c_int, c_void, c_uchar, c_char};
use std::option::Option;

pub type uint8_t = u8;
pub type uint16_t = u16;
pub type uint32_t = u32;

pub enum rtlsdr_dev { }
type rtlsdr_dev_t = rtlsdr_dev;

pub struct Device {
    dev: *mut rtlsdr_dev_t,
}

#[derive(Copy, Clone)]
#[repr(u32)]
#[derive(Debug)]
pub enum rtlsdr_tuner {
    RTLSDR_TUNER_UNKNOWN = 0,
    RTLSDR_TUNER_E4000 = 1,
    RTLSDR_TUNER_FC0012 = 2,
    RTLSDR_TUNER_FC0013 = 3,
    RTLSDR_TUNER_FC2580 = 4,
    RTLSDR_TUNER_R820T = 5,
    RTLSDR_TUNER_R828D = 6,
}

#[derive(Copy, Clone)]
#[derive(Debug)]
pub enum Error {
    NoError,
    Io,
    InvalidParam,
    Access,
    NoDevice,
    NotFound,
    Busy,
    Timeout,
    Overflow,
    Pipe,
    Interrupted,
    NoMem,
    NotSupported,
    Other,
}

pub type rtlsdr_read_async_cb_t = Option<unsafe extern "C" fn(buf: *mut c_uchar,
                                                              len: uint32_t,
                                                              ctx: *mut c_void)>;

#[link(name = "rtlsdr")]
extern "C" {
    fn rtlsdr_get_device_count() -> uint32_t;
    fn rtlsdr_get_device_name(index: uint32_t) -> *const c_char;
    fn rtlsdr_get_device_usb_strings(index: uint32_t,
                                     manufact: *mut c_char,
                                     product: *mut c_char,
                                     serial: *mut c_char)
                                     -> c_int;
    fn rtlsdr_get_index_by_serial(serial: *const c_char) -> c_int;

    fn rtlsdr_open(dev: *mut *mut rtlsdr_dev_t, index: uint32_t) -> c_int;
    fn rtlsdr_close(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_xtal_freq(dev: *mut rtlsdr_dev_t,
                            rtl_freq: uint32_t,
                            tuner_freq: uint32_t)
                            -> c_int;
    fn rtlsdr_get_xtal_freq(dev: *mut rtlsdr_dev_t,
                            rtl_freq: *mut uint32_t,
                            tuner_freq: *mut uint32_t)
                            -> c_int;
    fn rtlsdr_get_usb_strings(dev: *mut rtlsdr_dev_t,
                              manufact: *mut c_char,
                              product: *mut c_char,
                              serial: *mut c_char)
                              -> c_int;
    fn rtlsdr_write_eeprom(dev: *mut rtlsdr_dev_t,
                           data: *mut uint8_t,
                           offset: uint8_t,
                           len: uint16_t)
                           -> c_int;
    fn rtlsdr_read_eeprom(dev: *mut rtlsdr_dev_t,
                          data: *mut uint8_t,
                          offset: uint8_t,
                          len: uint16_t)
                          -> c_int;
    fn rtlsdr_set_center_freq(dev: *mut rtlsdr_dev_t, freq: uint32_t) -> c_int;
    fn rtlsdr_get_center_freq(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_freq_correction(dev: *mut rtlsdr_dev_t, ppm: c_int) -> c_int;
    fn rtlsdr_get_freq_correction(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_get_tuner_type(dev: *mut rtlsdr_dev_t) -> rtlsdr_tuner;
    fn rtlsdr_get_tuner_gains(dev: *mut rtlsdr_dev_t, gains: *mut c_int) -> c_int;
    fn rtlsdr_set_tuner_gain(dev: *mut rtlsdr_dev_t, gain: c_int) -> c_int;
    fn rtlsdr_set_tuner_bandwidth(dev: *mut rtlsdr_dev_t, bw: uint32_t) -> c_int;
    fn rtlsdr_get_tuner_gain(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_tuner_if_gain(dev: *mut rtlsdr_dev_t, stage: c_int, gain: c_int) -> c_int;
    fn rtlsdr_set_tuner_gain_mode(dev: *mut rtlsdr_dev_t, manual: c_int) -> c_int;
    fn rtlsdr_set_sample_rate(dev: *mut rtlsdr_dev_t, rate: uint32_t) -> c_int;
    fn rtlsdr_get_sample_rate(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_testmode(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_set_agc_mode(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_set_direct_sampling(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_get_direct_sampling(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_offset_tuning(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_get_offset_tuning(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_reset_buffer(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_read_sync(dev: *mut rtlsdr_dev_t,
                        buf: *mut c_void,
                        len: c_int,
                        n_read: *mut c_int)
                        -> c_int;
    fn rtlsdr_wait_async(dev: *mut rtlsdr_dev_t,
                         cb: rtlsdr_read_async_cb_t,
                         ctx: *mut c_void)
                         -> c_int;
    fn rtlsdr_read_async(dev: *mut rtlsdr_dev_t,
                         cb: rtlsdr_read_async_cb_t,
                         ctx: *mut c_void,
                         buf_num: uint32_t,
                         buf_len: uint32_t)
                         -> c_int;
    fn rtlsdr_cancel_async(dev: *mut rtlsdr_dev_t) -> c_int;
}

fn get_err_msg(e: c_int) -> Error {
    use Error::*;
    match e {
        0 => NoError,
        -1 => Io,
        -2 => InvalidParam,
        -3 => Access,
        -4 => NoDevice,
        -5 => NotFound,
        -6 => Busy,
        -7 => Timeout,
        -8 => Overflow,
        -9 => Pipe,
        -10 => Interrupted,
        -11 => NoMem,
        -12 => NotSupported,
        _ => Other,
    }
}

// pub fn get_device_count() -> i32 {}
// pub fn get_device_name(index: ) ->  {}
// pub fn get_device_usb_strings( ) ->  i32 {}
// pub fn get_index_by_serial( ) ->  {}

pub fn open(index: i32) -> (Device, Error) {
    unsafe {
        let mut dev: *mut rtlsdr_dev_t = std::ptr::null_mut();
        let err = rtlsdr_open(&mut dev as *mut *mut rtlsdr_dev_t, index as uint32_t);
        return (Device {dev: dev}, get_err_msg(err));
    }
}

impl Device {
    pub fn close(&self) -> Error {
        unsafe {
            return get_err_msg(rtlsdr_close(self.dev));
        }
    }
//     pub fn set_xtal_freq() -> Error {}
//     pub fn get_xtal_freq() -> Error {}
//     pub fn get_usb_strings() -> Error {}
//     pub fn write_eeprom() -> Error {}
//     pub fn read_eeprom() -> Error {}
//     pub fn set_center_freq() -> Error {}
//     pub fn get_center_freq() -> Error {}
//     pub fn set_freq_correction() -> Error {}
//     pub fn get_freq_correction() -> Error {}
//     pub fn get_tuner_type() -> rtlsdr_tuner {}
//     pub fn get_tuner_gains() -> Error {}
//     pub fn set_tuner_gain() -> Error {}
//     pub fn set_tuner_bandwidth() -> Error {}
//     pub fn get_tuner_gain() -> Error {}
//     pub fn set_tuner_if_gain() -> Error {}
//     pub fn set_tuner_gain_mode() -> Error {}
//     pub fn set_sample_rate() -> Error {}
//     pub fn get_sample_rate() -> Error {}
//     pub fn set_testmode() -> Error {}
//     pub fn set_agc_mode() -> Error {}
//     pub fn set_direct_sampling() -> Error {}
//     pub fn get_direct_sampling() -> Error {}
//     pub fn set_offset_tuning() -> Error {}
//     pub fn get_offset_tuning() -> Error {}
//     pub fn reset_buffer() -> Error {}
//     pub fn read_sync() -> Error {}
//     pub fn wait_async() -> Error {}
//     pub fn read_async() -> Error {}
//     pub fn cancel_async() -> Error {}
}

fn main() {
    println!("opening...");
    let (dev, err) = open(0);
    match err {
        Error::NoError => println!("open successful"),
        _ => return,
    }
    let e = dev.close();
    println!("dev close status: {:?}", e);
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};

use semver;
use git2;
use serde_json;

use app::App;
use dependency::Kind;
use util::{CargoResult, internal};

#[derive(Serialize, Deserialize, Debug)]
pub struct Crate {
    pub name: String,
    pub vers: String,
    pub deps: Vec<Dependency>,
    pub cksum: String,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: Option<bool>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Dependency {
    pub name: String,
    pub req: String,
    pub features: Vec<String>,
    pub optional: bool,
    pub default_features: bool,
    pub target: Option<String>,
    pub kind: Option<Kind>,
}

fn index_file(base: &Path, name: &str) -> PathBuf {
    let name = name.chars()
        .flat_map(|c| c.to_lowercase())
        .collect::<String>();
    match name.len() {
        1 => base.join("1").join(&name),
        2 => base.join("2").join(&name),
        3 => base.join("3").join(&name[..1]).join(&name),
        _ => base.join(&name[0..2]).join(&name[2..4]).join(&name),
    }
}

pub fn add_crate(app: &App, krate: &Crate) -> CargoResult<()> {
    let repo = app.git_repo.lock().unwrap();
    let repo = &*repo;
    let repo_path = repo.workdir().unwrap();
    let dst = index_file(repo_path, &krate.name);

    commit_and_push(repo, || {
        // Add the crate to its relevant file
        fs::create_dir_all(dst.parent().unwrap())?;
        let mut prev = String::new();
        if fs::metadata(&dst).is_ok() {
            File::open(&dst).and_then(
                |mut f| f.read_to_string(&mut prev),
            )?;
        }
        let s = serde_json::to_string(krate).unwrap();
        let new = prev + &s;
        let mut f = File::create(&dst)?;
        f.write_all(new.as_bytes())?;
        f.write_all(b"\n")?;

        Ok((
            format!("Updating crate `{}#{}`", krate.name, krate.vers),
            dst.clone(),
        ))
    })
}

/// Yanks or unyanks a crate version. This requires finding the index
/// file, deserlialise the crate from JSON, change the yank boolean to
/// `true` or `false`, write all the lines back out, and commit and
/// push the changes.
pub fn yank(app: &App, krate: &str, version: &semver::Version, yanked: bool) -> CargoResult<()> {
    let repo = app.git_repo.lock().unwrap();
    let repo_path = repo.workdir().unwrap();
    let dst = index_file(repo_path, krate);

    commit_and_push(&repo, || {
        let mut prev = String::new();
        File::open(&dst).and_then(
            |mut f| f.read_to_string(&mut prev),
        )?;
        let new = prev.lines()
            .map(|line| {
                let mut git_crate = serde_json::from_str::<Crate>(line).map_err(|_| {
                    internal(&format_args!("couldn't decode: `{}`", line))
                })?;
                if git_crate.name != krate || git_crate.vers != version.to_string() {
                    return Ok(line.to_string());
                }
                git_crate.yanked = Some(yanked);
                Ok(serde_json::to_string(&git_crate).unwrap())
            })
            .collect::<CargoResult<Vec<String>>>();
        let new = new?.join("\n");
        let mut f = File::create(&dst)?;
        f.write_all(new.as_bytes())?;
        f.write_all(b"\n")?;

        Ok((
            format!(
                "{} crate `{}#{}`",
                if yanked { "Yanking" } else { "Unyanking" },
                krate,
                version
            ),
            dst.clone(),
        ))
    })
}

/// Commits and pushes to the crates.io index.
///
/// There are currently 2 instances of the crates.io backend running
/// on Heroku, and they race against each other e.g. if 2 pushes occur,
/// then one will succeed while the other will need to be rebased before
/// being pushed.
///
/// A maximum of 20 attempts to commit and push to the index currently
/// accounts for the amount of traffic publishing crates, though this may
/// have to be changed in the future.
///
/// Notes:
/// Currently, this function is called on the HTTP thread and is blocking.
/// Spawning a separate thread for this function means that the request
/// can return without waiting for completion, and other methods of
/// notifying upon completion or error can be used.
fn commit_and_push<F>(repo: &git2::Repository, mut f: F) -> CargoResult<()>
where
    F: FnMut() -> CargoResult<(String, PathBuf)>,
{
    let repo_path = repo.workdir().unwrap();

    // Attempt to commit in a loop. It's possible that we're going to need to
    // rebase our repository, and after that it's possible that we're going to
    // race to commit the changes. For now we just cap out the maximum number of
    // retries at a fixed number.
    for _ in 0..20 {
        let (msg, dst) = f()?;

        // git add $file
        let mut index = repo.index()?;
        let mut repo_path = repo_path.iter();
        let dst = dst.iter()
            .skip_while(|s| Some(*s) == repo_path.next())
            .collect::<PathBuf>();
        index.add_path(&dst)?;
        index.write()?;
        let tree_id = index.write_tree()?;
        let tree = repo.find_tree(tree_id)?;

        // git commit -m "..."
        let head = repo.head()?;
        let parent = repo.find_commit(head.target().unwrap())?;
        let sig = repo.signature()?;
        repo.commit(
            Some("HEAD"),
            &sig,
            &sig,
            &msg,
            &tree,
            &[&parent],
        )?;

        // git push
        let mut ref_status = None;
        let mut origin = repo.find_remote("origin")?;
        let res = {
            let mut callbacks = git2::RemoteCallbacks::new();
            callbacks.credentials(credentials);
            callbacks.push_update_reference(|refname, status| {
                assert_eq!(refname, "refs/heads/master");
                ref_status = status.map(|s| s.to_string());
                Ok(())
            });
            let mut opts = git2::PushOptions::new();
            opts.remote_callbacks(callbacks);
            origin.push(&["refs/heads/master"], Some(&mut opts))
        };
        match res {
            Ok(()) if ref_status.is_none() => return Ok(()),
            Ok(()) => info!("failed to push a ref: {:?}", ref_status),
            Err(e) => info!("failure to push: {}", e),
        }

        let mut callbacks = git2::RemoteCallbacks::new();
        callbacks.credentials(credentials);
        origin.update_tips(
            Some(&mut callbacks),
            true,
            git2::AutotagOption::Unspecified,
            None,
        )?;

        // Ok, we need to update, so fetch and reset --hard
        origin.fetch(&["refs/heads/*:refs/heads/*"], None, None)?;
        let head = repo.head()?.target().unwrap();
        let obj = repo.find_object(head, None)?;
        repo.reset(&obj, git2::ResetType::Hard, None)?;
    }

    Err(internal("Too many rebase failures"))
}

pub fn credentials(
    _user: &str,
    _user_from_url: Option<&str>,
    _cred: git2::CredentialType,
) -> Result<git2::Cred, git2::Error> {
    match (env::var("GIT_HTTP_USER"), env::var("GIT_HTTP_PWD")) {
        (Ok(u), Ok(p)) => git2::Cred::userpass_plaintext(&u, &p),
        _ => Err(git2::Error::from_str("no authentication set")),
    }
}
<commit_msg>cargo fmt<commit_after>use std::collections::HashMap;
use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};

use semver;
use git2;
use serde_json;

use app::App;
use dependency::Kind;
use util::{CargoResult, internal};

#[derive(Serialize, Deserialize, Debug)]
pub struct Crate {
    pub name: String,
    pub vers: String,
    pub deps: Vec<Dependency>,
    pub cksum: String,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: Option<bool>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Dependency {
    pub name: String,
    pub req: String,
    pub features: Vec<String>,
    pub optional: bool,
    pub default_features: bool,
    pub target: Option<String>,
    pub kind: Option<Kind>,
}

fn index_file(base: &Path, name: &str) -> PathBuf {
    let name = name.chars()
        .flat_map(|c| c.to_lowercase())
        .collect::<String>();
    match name.len() {
        1 => base.join("1").join(&name),
        2 => base.join("2").join(&name),
        3 => base.join("3").join(&name[..1]).join(&name),
        _ => base.join(&name[0..2]).join(&name[2..4]).join(&name),
    }
}

pub fn add_crate(app: &App, krate: &Crate) -> CargoResult<()> {
    let repo = app.git_repo.lock().unwrap();
    let repo = &*repo;
    let repo_path = repo.workdir().unwrap();
    let dst = index_file(repo_path, &krate.name);

    commit_and_push(repo, || {
        // Add the crate to its relevant file
        fs::create_dir_all(dst.parent().unwrap())?;
        let mut prev = String::new();
        if fs::metadata(&dst).is_ok() {
            File::open(&dst).and_then(
                |mut f| f.read_to_string(&mut prev),
            )?;
        }
        let s = serde_json::to_string(krate).unwrap();
        let new = prev + &s;
        let mut f = File::create(&dst)?;
        f.write_all(new.as_bytes())?;
        f.write_all(b"\n")?;

        Ok((
            format!("Updating crate `{}#{}`", krate.name, krate.vers),
            dst.clone(),
        ))
    })
}

/// Yanks or unyanks a crate version. This requires finding the index
/// file, deserlialise the crate from JSON, change the yank boolean to
/// `true` or `false`, write all the lines back out, and commit and
/// push the changes.
pub fn yank(app: &App, krate: &str, version: &semver::Version, yanked: bool) -> CargoResult<()> {
    let repo = app.git_repo.lock().unwrap();
    let repo_path = repo.workdir().unwrap();
    let dst = index_file(repo_path, krate);

    commit_and_push(&repo, || {
        let mut prev = String::new();
        File::open(&dst).and_then(
            |mut f| f.read_to_string(&mut prev),
        )?;
        let new = prev.lines()
            .map(|line| {
                let mut git_crate = serde_json::from_str::<Crate>(line).map_err(|_| {
                    internal(&format_args!("couldn't decode: `{}`", line))
                })?;
                if git_crate.name != krate || git_crate.vers != version.to_string() {
                    return Ok(line.to_string());
                }
                git_crate.yanked = Some(yanked);
                Ok(serde_json::to_string(&git_crate).unwrap())
            })
            .collect::<CargoResult<Vec<String>>>();
        let new = new?.join("\n");
        let mut f = File::create(&dst)?;
        f.write_all(new.as_bytes())?;
        f.write_all(b"\n")?;

        Ok((
            format!(
                "{} crate `{}#{}`",
                if yanked { "Yanking" } else { "Unyanking" },
                krate,
                version
            ),
            dst.clone(),
        ))
    })
}

/// Commits and pushes to the crates.io index.
///
/// There are currently 2 instances of the crates.io backend running
/// on Heroku, and they race against each other e.g. if 2 pushes occur,
/// then one will succeed while the other will need to be rebased before
/// being pushed.
///
/// A maximum of 20 attempts to commit and push to the index currently
/// accounts for the amount of traffic publishing crates, though this may
/// have to be changed in the future.
///
/// Notes:
/// Currently, this function is called on the HTTP thread and is blocking.
/// Spawning a separate thread for this function means that the request
/// can return without waiting for completion, and other methods of
/// notifying upon completion or error can be used.
fn commit_and_push<F>(repo: &git2::Repository, mut f: F) -> CargoResult<()>
where
    F: FnMut() -> CargoResult<(String, PathBuf)>,
{
    let repo_path = repo.workdir().unwrap();

    // Attempt to commit in a loop. It's possible that we're going to need to
    // rebase our repository, and after that it's possible that we're going to
    // race to commit the changes. For now we just cap out the maximum number of
    // retries at a fixed number.
    for _ in 0..20 {
        let (msg, dst) = f()?;

        // git add $file
        let mut index = repo.index()?;
        let mut repo_path = repo_path.iter();
        let dst = dst.iter()
            .skip_while(|s| Some(*s) == repo_path.next())
            .collect::<PathBuf>();
        index.add_path(&dst)?;
        index.write()?;
        let tree_id = index.write_tree()?;
        let tree = repo.find_tree(tree_id)?;

        // git commit -m "..."
        let head = repo.head()?;
        let parent = repo.find_commit(head.target().unwrap())?;
        let sig = repo.signature()?;
        repo.commit(
            Some("HEAD"),
            &sig,
            &sig,
            &msg,
            &tree,
            &[&parent],
        )?;

        // git push
        let mut ref_status = None;
        let mut origin = repo.find_remote("origin")?;
        let res = {
            let mut callbacks = git2::RemoteCallbacks::new();
            callbacks.credentials(credentials);
            callbacks.push_update_reference(|refname, status| {
                assert_eq!(refname, "refs/heads/master");
                ref_status = status.map(|s| s.to_string());
                Ok(())
            });
            let mut opts = git2::PushOptions::new();
            opts.remote_callbacks(callbacks);
            origin.push(&["refs/heads/master"], Some(&mut opts))
        };
        match res {
            Ok(()) if ref_status.is_none() => return Ok(()),
            Ok(()) => info!("failed to push a ref: {:?}", ref_status),
            Err(e) => info!("failure to push: {}", e),
        }

        let mut callbacks = git2::RemoteCallbacks::new();
        callbacks.credentials(credentials);
        origin.update_tips(
            Some(&mut callbacks),
            true,
            git2::AutotagOption::Unspecified,
            None,
        )?;

        // Ok, we need to update, so fetch and reset --hard
        origin.fetch(&["refs/heads/*:refs/heads/*"], None, None)?;
        let head = repo.head()?.target().unwrap();
        let obj = repo.find_object(head, None)?;
        repo.reset(&obj, git2::ResetType::Hard, None)?;
    }

    Err(internal("Too many rebase failures"))
}

pub fn credentials(
    _user: &str,
    _user_from_url: Option<&str>,
    _cred: git2::CredentialType,
) -> Result<git2::Cred, git2::Error> {
    match (env::var("GIT_HTTP_USER"), env::var("GIT_HTTP_PWD")) {
        (Ok(u), Ok(p)) => git2::Cred::userpass_plaintext(&u, &p),
        _ => Err(git2::Error::from_str("no authentication set")),
    }
}
<|endoftext|>


<commit_before>use gtk;
use gtk::prelude::*;

const GUI_XML: &'static str = r#"
<interface>
  <object class="GtkWindow" id="window">
    <property name="title">Rusty Microphone</property>
    <child>
      <object class="GtkComboBoxText" id="dropdown">
      </object>
    </child>
  </object>
</interface>
"#;

pub fn start_gui() -> Result<(), String> {
    let pa = try!(::audio::init().map_err(|e| e.to_string()));
    let microphones = try!(::audio::get_device_list(&pa).map_err(|e| e.to_string()));

    try!(gtk::init().map_err(|_| "Failed to initialize GTK."));

    let gtk_builder = try!(create_window(microphones));

    let dropdown: gtk::ComboBoxText = try!(
        gtk_builder.get_object("dropdown")
                   .ok_or("GUI does not contain an object with id 'dropdown'")
    );
    dropdown.connect_changed(|ref dropdown| {
        println!("{}", dropdown.get_active_id().unwrap());
        //This callback can now mutate state on the same level as our
        //other logic to get the list of microphones
    });

    gtk::main();
    Ok(())
}

fn create_window(microphones: Vec<(u32, String)>) -> Result<gtk::Builder, String> {
    let gtk_builder = gtk::Builder::new_from_string(GUI_XML);
    let window: gtk::Window = try!(
        gtk_builder.get_object("window")
                   .ok_or("GUI does not contain an object with id 'window'")
    );
    window.set_default_size(300, 300);
    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });
    window.show_all();

    let dropdown: gtk::ComboBoxText = try!(
        gtk_builder.get_object("dropdown")
                   .ok_or("GUI does not contain an object with id 'dropdown'")
    );
    set_dropdown_items(&dropdown, microphones);

    Ok(gtk_builder)
}

fn set_dropdown_items(dropdown: &gtk::ComboBoxText, microphones: Vec<(u32, String)>) {
    for (index, name) in microphones {
        dropdown.append(Some(format!("{}", index).as_ref()), name.as_ref());
    }
}
<commit_msg>Added changing of mutable state from dropdown<commit_after>use gtk;
use gtk::prelude::*;
use std::cell::Cell;

const GUI_XML: &'static str = r#"
<interface>
  <object class="GtkWindow" id="window">
    <property name="title">Rusty Microphone</property>
    <child>
      <object class="GtkComboBoxText" id="dropdown">
      </object>
    </child>
  </object>
</interface>
"#;

pub fn start_gui() -> Result<(), String> {
    let pa = try!(::audio::init().map_err(|e| e.to_string()));
    let microphones = try!(::audio::get_device_list(&pa).map_err(|e| e.to_string()));
    let selected_mic: Cell<Option<u32>> = Cell::new(None);

    try!(gtk::init().map_err(|_| "Failed to initialize GTK."));

    let gtk_builder = try!(create_window(microphones));

    let dropdown: gtk::ComboBoxText = try!(
        gtk_builder.get_object("dropdown")
                   .ok_or("GUI does not contain an object with id 'dropdown'")
    );
    dropdown.connect_changed(move |dropdown: &gtk::ComboBoxText| {
        selected_mic.set(dropdown.get_active_id().and_then(|id| id.parse().ok()));
        println!("{}", selected_mic.get().unwrap());
    });

    gtk::main();
    Ok(())
}

fn create_window(microphones: Vec<(u32, String)>) -> Result<gtk::Builder, String> {
    let gtk_builder = gtk::Builder::new_from_string(GUI_XML);
    let window: gtk::Window = try!(
        gtk_builder.get_object("window")
                   .ok_or("GUI does not contain an object with id 'window'")
    );
    window.set_default_size(300, 300);
    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });
    window.show_all();

    let dropdown: gtk::ComboBoxText = try!(
        gtk_builder.get_object("dropdown")
                   .ok_or("GUI does not contain an object with id 'dropdown'")
    );
    set_dropdown_items(&dropdown, microphones);

    Ok(gtk_builder)
}

fn set_dropdown_items(dropdown: &gtk::ComboBoxText, microphones: Vec<(u32, String)>) {
    for (index, name) in microphones {
        dropdown.append(Some(format!("{}", index).as_ref()), name.as_ref());
    }
}
<|endoftext|>


<commit_before>use bytecount::naive_count_32;
use regex::Regex;

lazy_static! {
    static ref PAT_TOKENS: Regex = Regex::new(r#"(?xm)
          (?:\(:)
        | (?:=>\n\x20+)
        | (?:\n+\x20+)
        | "
        | =
        | \(
        | \)
        | \s+
        | [^\(\)=\s"]+"#).expect("Failed to compile lexer regex");
}

#[derive(Debug, PartialEq)]
pub enum Token<'a> {
    StartBlock(i32),
    RightParen,
    Rocket(i32),
    Dedent,
    Text(i32, &'a str),
    Quote(i32),
}

pub fn lex(data: &str) -> Vec<Token> {
    let data_bytes = data.as_bytes();
    let mut lineno: i32 = 0;
    let mut last_match_start: usize = 0;
    let mut tokens: Vec<Token> = vec![];
    let mut indent: Vec<usize> = vec![0];

    for pat_match in PAT_TOKENS.find_iter(data) {
        lineno += naive_count_32(&data_bytes[last_match_start..pat_match.start()], b'\n') as i32;
        last_match_start = pat_match.start();
        let token_text = pat_match.as_str();
        let bytes = token_text.as_bytes();

        let token = match bytes[0] {
            b')' => Token::RightParen,
            b'"' => Token::Quote(lineno),
            _ if bytes == b"(:" => Token::StartBlock(lineno),
            _ if bytes.starts_with(b"=>\n") => {
                indent.push(bytes.len() - 3);
                Token::Rocket(lineno)
            }
            _ if bytes.starts_with(b"\n") => {
                let mut current_indentation_level =
                    *(indent.last().expect("Indentation stack is empty"));
                let new_indentation_level = token_text.len() - 1;

                while new_indentation_level < current_indentation_level {
                    indent.pop();
                    current_indentation_level =
                        *(indent.last().expect("Indentation stack is empty"));
                    tokens.push(Token::Dedent);
                }

                let new_end = token_text.len() - current_indentation_level;
                Token::Text(lineno, &token_text[..new_end])
            }
            _ => Token::Text(lineno, token_text),
        };

        tokens.push(token)
    }

    while indent.len() > 1 {
        tokens.push(Token::Dedent);
        indent.pop();
    }

    tokens
}

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

    #[test]
    fn test_empty() {
        assert_eq!(lex(""), vec![]);
    }

    #[test]
    fn test_expression() {
        assert_eq!(
            lex(r#"(:foo bar (:a "b c") "baz" )"#),
            vec![
                Token::StartBlock(0),
                Token::Text(0, "foo"),
                Token::Text(0, " "),
                Token::Text(0, "bar"),
                Token::Text(0, " "),
                Token::StartBlock(0),
                Token::Text(0, "a"),
                Token::Text(0, " "),
                Token::Quote(0),
                Token::Text(0, "b"),
                Token::Text(0, " "),
                Token::Text(0, "c"),
                Token::Quote(0),
                Token::RightParen,
                Token::Text(0, " "),
                Token::Quote(0),
                Token::Text(0, "baz"),
                Token::Quote(0),
                Token::Text(0, " "),
                Token::RightParen,
            ]
        );
    }

    #[test]
    fn test_rocket() {
        assert_eq!(
            lex(
                "
(:note \"a title\" =>
  stuff  1

  stuff 2

  (:note =>
    more stuff

    second =>paragraph

  closing nested

\x20\x20

(:h2 foo)"
            ),
            vec![
                Token::Text(0, "\n"),
                Token::StartBlock(1),
                Token::Text(1, "note"),
                Token::Text(1, " "),
                Token::Quote(1),
                Token::Text(1, "a"),
                Token::Text(1, " "),
                Token::Text(1, "title"),
                Token::Quote(1),
                Token::Text(1, " "),
                Token::Rocket(1),
                Token::Text(2, "stuff"),
                Token::Text(2, "  "),
                Token::Text(2, "1"),
                Token::Text(2, "\n\n"),
                Token::Text(4, "stuff"),
                Token::Text(4, " "),
                Token::Text(4, "2"),
                Token::Text(4, "\n\n"),
                Token::StartBlock(6),
                Token::Text(6, "note"),
                Token::Text(6, " "),
                Token::Rocket(6),
                Token::Text(7, "more"),
                Token::Text(7, " "),
                Token::Text(7, "stuff"),
                Token::Text(7, "\n\n"),
                Token::Text(9, "second"),
                Token::Text(9, " "),
                Token::Text(9, "="),
                Token::Text(9, ">paragraph"),
                Token::Dedent,
                Token::Text(9, "\n\n"),
                Token::Text(11, "closing"),
                Token::Text(11, " "),
                Token::Text(11, "nested"),
                Token::Text(11, "\n\n"),
                Token::Dedent,
                Token::Text(13, "\n\n"),
                Token::StartBlock(15),
                Token::Text(15, "h2"),
                Token::Text(15, " "),
                Token::Text(15, "foo"),
                Token::RightParen,
            ]
        );
    }

    #[test]
    fn test_rocket_indentation() {
        assert_eq!(
            lex(
                r#"
(:note =>
  stuff
    stuff"#.trim()
            ),
            vec![
                Token::StartBlock(0),
                Token::Text(0, "note"),
                Token::Text(0, " "),
                Token::Rocket(0),
                Token::Text(1, "stuff"),
                Token::Text(1, "\n  "),
                Token::Text(2, "stuff"),
                Token::Dedent,
            ]
        );
    }
}
<commit_msg>lex: Properly emit Dedent more often<commit_after>use bytecount::naive_count_32;
use regex::Regex;

lazy_static! {
    static ref PAT_TOKENS: Regex = Regex::new(r#"(?xm)
          (?:\(:)
        | (?:=>\n\x20+)
        | (?:\n+\x20+)
        | "
        | =
        | \(
        | \)
        | \s+
        | [^\(\)=\s"]+"#).expect("Failed to compile lexer regex");
}

#[derive(Debug, PartialEq)]
pub enum Token<'a> {
    StartBlock(i32),
    RightParen,
    Rocket(i32),
    Dedent,
    Text(i32, &'a str),
    Quote(i32),
}

pub fn lex(data: &str) -> Vec<Token> {
    let data_bytes = data.as_bytes();
    let mut lineno: i32 = 0;
    let mut last_match_start: usize = 0;
    let mut tokens: Vec<Token> = vec![];
    let mut indent: Vec<usize> = vec![0];

    for pat_match in PAT_TOKENS.find_iter(data) {
        lineno += naive_count_32(&data_bytes[last_match_start..pat_match.start()], b'\n') as i32;
        last_match_start = pat_match.start();
        let token_text = pat_match.as_str();
        let bytes = token_text.as_bytes();

        let token = match bytes[0] {
            b')' => Token::RightParen,
            b'"' => Token::Quote(lineno),
            _ if bytes == b"(:" => Token::StartBlock(lineno),
            _ if bytes.starts_with(b"=>\n") => {
                indent.push(bytes.len() - 3);
                Token::Rocket(lineno)
            }
            _ if bytes.starts_with(b"\n") => {
                let mut current_indentation_level =
                    *(indent.last().expect("Indentation stack is empty"));
                let new_indentation_level = naive_count_32(bytes, b' ');

                while new_indentation_level < current_indentation_level {
                    indent.pop();
                    current_indentation_level =
                        *(indent.last().expect("Indentation stack is empty"));
                    tokens.push(Token::Dedent);
                }

                let new_end = token_text.len() - current_indentation_level;
                Token::Text(lineno, &token_text[..new_end])
            }
            _ => Token::Text(lineno, token_text),
        };

        tokens.push(token)
    }

    while indent.len() > 1 {
        tokens.push(Token::Dedent);
        indent.pop();
    }

    tokens
}

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

    #[test]
    fn test_empty() {
        assert_eq!(lex(""), vec![]);
    }

    #[test]
    fn test_expression() {
        assert_eq!(
            lex(r#"(:foo bar (:a "b c") "baz" )"#),
            vec![
                Token::StartBlock(0),
                Token::Text(0, "foo"),
                Token::Text(0, " "),
                Token::Text(0, "bar"),
                Token::Text(0, " "),
                Token::StartBlock(0),
                Token::Text(0, "a"),
                Token::Text(0, " "),
                Token::Quote(0),
                Token::Text(0, "b"),
                Token::Text(0, " "),
                Token::Text(0, "c"),
                Token::Quote(0),
                Token::RightParen,
                Token::Text(0, " "),
                Token::Quote(0),
                Token::Text(0, "baz"),
                Token::Quote(0),
                Token::Text(0, " "),
                Token::RightParen,
            ]
        );
    }

    #[test]
    fn test_rocket() {
        assert_eq!(
            lex(
                "
(:note \"a title\" =>
  stuff  1

  stuff 2

  (:note =>
    more stuff

    second =>paragraph

  closing nested

\x20\x20

(:h2 foo)"
            ),
            vec![
                Token::Text(0, "\n"),
                Token::StartBlock(1),
                Token::Text(1, "note"),
                Token::Text(1, " "),
                Token::Quote(1),
                Token::Text(1, "a"),
                Token::Text(1, " "),
                Token::Text(1, "title"),
                Token::Quote(1),
                Token::Text(1, " "),
                Token::Rocket(1),
                Token::Text(2, "stuff"),
                Token::Text(2, "  "),
                Token::Text(2, "1"),
                Token::Text(2, "\n\n"),
                Token::Text(4, "stuff"),
                Token::Text(4, " "),
                Token::Text(4, "2"),
                Token::Text(4, "\n\n"),
                Token::StartBlock(6),
                Token::Text(6, "note"),
                Token::Text(6, " "),
                Token::Rocket(6),
                Token::Text(7, "more"),
                Token::Text(7, " "),
                Token::Text(7, "stuff"),
                Token::Text(7, "\n\n"),
                Token::Text(9, "second"),
                Token::Text(9, " "),
                Token::Text(9, "="),
                Token::Text(9, ">paragraph"),
                Token::Dedent,
                Token::Text(9, "\n\n"),
                Token::Text(11, "closing"),
                Token::Text(11, " "),
                Token::Text(11, "nested"),
                Token::Text(11, "\n\n"),
                Token::Dedent,
                Token::Text(13, "\n\n"),
                Token::StartBlock(15),
                Token::Text(15, "h2"),
                Token::Text(15, " "),
                Token::Text(15, "foo"),
                Token::RightParen,
            ]
        );
    }

    #[test]
    fn test_rocket_indentation() {
        assert_eq!(
            lex(
                r#"
(:note =>
  stuff
    stuff"#.trim()
            ),
            vec![
                Token::StartBlock(0),
                Token::Text(0, "note"),
                Token::Text(0, " "),
                Token::Rocket(0),
                Token::Text(1, "stuff"),
                Token::Text(1, "\n  "),
                Token::Text(2, "stuff"),
                Token::Dedent,
            ]
        );
    }

    #[test]
    fn test_multiline() {
        assert_eq!(
            lex(
                "
(:h2 =>
  Example

(:`` use
<database>)"
                    .trim()
            ),
            vec![
                Token::StartBlock(0),
                Token::Text(0, "h2"),
                Token::Text(0, " "),
                Token::Rocket(0),
                Token::Text(1, "Example"),
                Token::Dedent,
                Token::Text(1, "\n\n\n"),
                Token::StartBlock(4),
                Token::Text(4, "``"),
                Token::Text(4, " "),
                Token::Text(4, "use"),
                Token::Text(4, "\n"),
                Token::Text(5, "<database>"),
                Token::RightParen,
            ]
        );
    }
}
<|endoftext|>


<commit_before>
pub trait BaseTime {
  pub const Self MIN;
  pub const Self MAX;
  pub const Self NEVER;
}
impl BaseTime for i64 {

}

pub trait Field {
  type Data = Self;
  const unique_identifier: u64;
}

struct ExtendedTime <Base: BaseTime> {
  base: Base,
  iteration: u64,
  id: SiphashID,
}

pub trait Basics {
  type Time: BaseTime;
  type Constants;
}

pub trait Accessor {
  fn get <Type: Field> (&mut self, id: SiphashID)->& Option <Field::Data>;
}

pub trait Mutator <B: Basics>: Accessor {
  fn get_mutable <Type: Field> (&mut self, id: SiphashID)->& mut Option <Field::Data>;
  fn set <Type: Field> (&mut self, id: SiphashID, Option <Field::Data> data);
  fn random_bits (&mut self, bits:u32)->u64;
  fn random_id (&mut self)->SiphashID;
  fn now (& self)->B::Time;
  fn constants (& self)->& B::Constants;
}
pub trait PredictorAccessor <B: Basics>: Accessor {

}

pub type Event =Box <Fn (&mut Mutator)>;
enum Prediction <Time: BaseTime> {
  Nothing,
  Immediately (Event),
  At (Time, Event),
}

pub trait TimeSteward <B: Basics> {
  pub type A: Accessor;
  pub type M: Mutator;
  pub type P: PredictorAccessor;
  pub type Predictor = Box <Fn(&mut P)->Prediction>;
  fn new (constants: B::Constants, predictors: Vec<Predictor>)->Self;
}

pub trait FlatTimeSteward <B: Basics>:TimeSteward <B> {

}

 #[test]
fn it_works() {
}
<commit_msg>More implementing<commit_after>
pub trait BaseTime {
  pub const Self MIN;
  pub const Self MAX;
  pub const Self NEVER;
}
impl BaseTime for i64 {

}

pub trait Field {
  type Data = Self;
  const unique_identifier: u64;
}

#[derive (Clone, PartialEq, Eq, PartialOrd, Ord)]
struct GenericExtendedTime <Base: BaseTime> {
  base: Base,
  iteration: u64,
  id: SiphashID,
}

pub trait Basics {
  type Time: BaseTime;
  type Constants;
}
type ExtendedTime <B: Basics> = GenericExtendedTime <B::Time>;

pub trait Accessor {
  pub fn get <Type: Field> (&mut self, id: SiphashID)-> Option <& Field::Data>;
}

pub trait Mutator <B: Basics>: Accessor {
  pub fn get_mutable <Type: Field> (&mut self, id: SiphashID)->& mut Option <Field::Data>;
  pub fn set <Type: Field> (&mut self, id: SiphashID, Option <Field::Data> data);
  pub fn random_bits (&mut self, bits:u32)->u64;
  pub fn random_id (&mut self)->SiphashID;
  pub fn now (& self)->B::Time;
  pub fn constants (& self)->& B::Constants;
}
pub trait PredictorAccessor <B: Basics>: Accessor {

}

pub type Event =Box <Fn (&mut Mutator)>;
enum Prediction <Time: BaseTime> {
  Nothing,
  Immediately (Event),
  At (Time, Event),
}

pub trait TimeSteward <B: Basics> {
  pub type A: Accessor;
  pub type M: Mutator;
  pub type P: PredictorAccessor;
  pub type Predictor = Box <Fn(&mut P)->Prediction>;

  pub fn new (constants: B::Constants, predictors: Vec<Predictor>)->Self;
  pub fn insert_fiat_event (&mut self, time: B::Time, distinguisher: u64, Event)->bool;
  pub fn erase_fiat_event (&mut self, time: B::Time, distinguisher: u64)->bool;
  pub fn accessor_after (&mut self, time: B::Time)->Accessor;
}

pub trait FlatTimeSteward <B: Basics>:TimeSteward <B> {
  pub fn valid_strictly_between (& self)->(B::Time, B::Time);
}

pub struct StandardFlatTimeSteward <B: Basics> {
  entity_states: HashMap< SiphashID, Box <Any>>,
  last_change: B::Time,
  fiat_events: BTreeMap< ExtendedTime <B>, Event>,
  predictions: HashMap<ExtendedTime <B>,
  prediction_times:
}
struct StandardFlatTimeStewardAccessor <'a, B: Basics> {
  steward: &'a StandardFlatTimeSteward <B>,
}
impl <'a, B: Basics> Accessor for StandardFlatTimeStewardAccessor <'a, B: Basics> {
  pub fn get <Type: Field> (&mut self, id: SiphashID)-> Option <& Field::Data> {
    self.steward.entity_states.get (id).map (| box | box.downcast <Field::Data>.unwrap ().borrow ()
  }
}
struct StandardFlatTimeStewardMutator <'a, B: Basics> {
  steward: & mut 'a StandardFlatTimeSteward <B>,
}
impl <'a, B: Basics> Accessor for StandardFlatTimeStewardMutator <'a, B: Basics> {
  pub fn get <Type: Field> (&mut self, id: SiphashID)-> Option <& Field::Data> {
    self.steward.entity_states.get (id)
  }
}

impl <B: Basics> TimeSteward <B> for StandardFlatTimeSteward <B> {
  pub type A: StandardFlatTimeStewardAccessor;
  pub type M: StandardFlatTimeStewardMutator;
  pub type P: StandardFlatTimeStewardPredictorAccessor;
  pub type Predictor = Box <Fn(&mut P)->Prediction>;

  pub fn new (constants: B::Constants, predictors: Vec<Predictor>)->Self;
  pub fn insert_fiat_event (&mut self, time: B::Time, distinguisher: u64, Event)->bool;
  pub fn erase_fiat_event (&mut self, time: B::Time, distinguisher: u64)->bool;
  pub fn accessor_after (&mut self, time: B::Time)->Accessor;
}

 #[test]
fn it_works() {
}
<|endoftext|>


<commit_before>#![doc(html_logo_url = "https://zzeroo.github.io/share/zzeroo-logo.png",
       html_favicon_url = "https://zzeroo.github.io/share/favicon.ico",
html_root_url = "https://zzeroo.com/")]
//! This is an 'hopefully' safe Rust interface for the [libmodbus](http://libmodbus.org/) C library from http://libmodbus.org/.
//!
//! [libmodbus](http://libmodbus.org/) is a library to send/receive data with a device which respects the Modbus protocol.
//! This library contains various backends to communicate over different networks (eg. serial in RTU mode or Ethernet in TCP/IPv6).
//! The http://www.modbus.org site provides documentation about the protocol at http://www.modbus.org/specs.php.
//!
//! libmodbus provides an abstraction of the lower communication layers and offers the same API on all supported platforms.
//!
//! This documentation presents an overview of libmodbus concepts, describes how libmodbus abstracts Modbus communication with
//! different hardware and platforms and provides a reference manual for the functions provided by the libmodbus library.
//!
//! ## Contexts
//!
//! The Modbus protocol contains many variants (eg. serial RTU or Ehternet TCP), to ease the implementation of a variant,
//! the library was designed to use a backend for each variant.
//! The backends are also a convenient way to fulfill other requirements (eg. real-time operations). Each backend offers a specific function to create a new modbus_t context.
//! The modbus_t context is an opaque structure containing all necessary information to establish a connection with others Modbus devices according to the selected variant.
//!
//! You can choose the best context for your needs among:
//!
//! * [RTU Context](trait.ModbusRTU.html)
//! * [TCP (IPv4) Context](trait.ModbusTCP.html)
//! * [TCP PI (IPv4 and IPv6) Context](trait.ModbusTCPPI.html)
//!
//! ### [RTU Context](trait.ModbusRTU.html)
//!
//! The RTU backend (Remote Terminal Unit) is used in serial communication and makes use of a compact, binary representation of the data for protocol communication.
//! The RTU format follows the commands/data with a cyclic redundancy check checksum as an error check mechanism to ensure the reliability of data.
//! Modbus RTU is the most common implementation available for Modbus. A Modbus RTU message must be transmitted continuously without inter-character hesitations
//! (extract from Wikipedia, Modbus, http://en.wikipedia.org/wiki/Modbus (as of Mar. 13, 2011, 20:51 GMT).
//!
//! The Modbus RTU framing calls a slave, a device/service which handle Modbus requests, and a master, a client which send requests. The communication is always initiated by the master.
//!
//! Many Modbus devices can be connected together on the same physical link so before sending a message, you must set the slave (receiver) with modbus_set_slave(3).
//! If you’re running a slave, its slave number will be used to filter received messages.
//!
//! The libmodbus implementation of RTU isn’t time based as stated in original Modbus specification,
//! instead all bytes are sent as fast as possible and a response or an indication is considered complete when all expected characters have been received.
//! This implementation offers very fast communication but you must take care to set a response timeout of slaves less than response timeout of master
//! (ortherwise other slaves may ignore master requests when one of the slave is not responding).
//!
//! * Create a Modbus RTU context
//!     - [`new_rtu()`](struct.Modbus.html#method.new_rtu)
//!
//! * Set the serial mode
//!     - [`rtu_get_serial_mode()`](struct.Modbus.html#method.rtu_get_serial_mode), [`rtu_set_serial_mode()`](struct.Modbus.html#method.rtu_set_serial_mode), [`rtu_get_rts()`](struct.Modbus.html#method.rtu_get_rts), [`rtu_set_rts()`](struct.Modbus.html#method.rtu_set_rts), [`rtu_set_custom_rts()`](struct.Modbus.html#method.rtu_set_custom_rts), [`rtu_get_rts_delay()`](struct.Modbus.html#method.rtu_get_rts_delay), [`rtu_set_rts_delay()`](struct.Modbus.html#method.rtu_set_rts_delay)
//!
//! ### [TCP (IPv4) Context](trait.ModbusTCP.html)
//! The TCP backend implements a Modbus variant used for communications over TCP/IPv4 networks.
//! It does not require a checksum calculation as lower layer takes care of the same.
//!
//! * Create a Modbus TCP context
//!     - [`new_tcp()`](struct.Modbus.html#method.new_tcp)
//!
//! ### [TCP PI (IPv4 and IPv6) Context](trait.ModbusTCPPI.html)
//! The TCP PI (Protocol Independent) backend implements a Modbus variant used for communications over TCP IPv4 and IPv6 networks.
//! It does not require a checksum calculation as lower layer takes care of the same.
//!
//! Contrary to the TCP IPv4 only backend, the TCP PI backend offers hostname resolution but it consumes about 1Kb of additional memory.
//!
//! * Create a Modbus TCP context
//!     - [`new_tcp_pi()`](struct.Modbus.html#method.new_tcp_pi)
//!
//! ### Common
//!
//! ### Connection
//!
//! ### [`Client`](trait.ModbusClient.html)
//!
//! The Modbus protocol defines different data types and functions to read and write them from/to remote devices.
//! The following functions are used by the clients to send Modbus requests:
//!
//! * Read data
//!     - [`read_bits()`](struct.Modbus.html#method.read_bitsmode), [`read_input_bits()`](struct.Modbus.html#method.read_input_bits), [`read_registers()`](struct.Modbus.html#method.read_registers), [`read_input_registers()`](struct.Modbus.html#method.read_input_registers), [`report_slave_id()`](struct.Modbus.html#method.report_slave_id)
//! * Write data
//!     - [`write_bit()`](struct.Modbus.html#method.write_bit), [`write_register()`](struct.Modbus.html#method.write_register), [`write_bits()`](struct.Modbus.html#method.write_bits), [`write_registers()`](struct.Modbus.html#method.write_registers)
//! * Write and read data
//!     - [`write_and_read_registers()`](struct.Modbus.html#method.write_and_read_registers)
//! * Raw requests
//!     - [`send_raw_request()`](struct.Modbus.html#method.send_raw_request), [`receive_confirmation()`](struct.Modbus.html#method.receive_confirmation)
//! * Reply an exception
//!     - [`reply_exception()`](struct.Modbus.html#method.reply_exception)
//!
//! ### [`Server`](trait.ModbusServer.html)
//!
//! The server is waiting for request from clients and must answer when it is concerned by the request. The libmodbus offers the following functions to handle requests:
//!
//! * Receive
//!     - [`receive()`](struct.Modbus.html#method.receive)
//! * Reply
//!     - [`reply()`](struct.Modbus.html#method.reply), [`reply_exception()`](struct.Modbus.html#method.reply_exception)
//!

// `error_chain!` can recurse deeply(3)
#![recursion_limit = "1024"]

extern crate libc;
extern crate libmodbus_sys;
#[macro_use] extern crate error_chain;

mod errors;
mod modbus_client;
mod modbus_rtu;
mod modbus_server;
mod modbus_tcp_pi;
mod modbus_tcp;
mod modbus;

pub use self::modbus_client::ModbusClient;
pub use self::modbus_rtu::{ModbusRTU, request_to_send_mode, serial_mode};
pub use self::modbus_server::ModbusServer;
pub use self::modbus_tcp_pi::ModbusTCPPI;
pub use self::modbus_tcp::ModbusTCP;
pub use self::modbus::Modbus;

pub use libmodbus_sys::MODBUS_TCP_DEFAULT_PORT;
pub use libmodbus_sys::MODBUS_MAX_ADU_LENGTH;
<commit_msg>Make errors module public<commit_after>#![doc(html_logo_url = "https://zzeroo.github.io/share/zzeroo-logo.png",
       html_favicon_url = "https://zzeroo.github.io/share/favicon.ico",
html_root_url = "https://zzeroo.com/")]
//! This is an 'hopefully' safe Rust interface for the [libmodbus](http://libmodbus.org/) C library from http://libmodbus.org/.
//!
//! [libmodbus](http://libmodbus.org/) is a library to send/receive data with a device which respects the Modbus protocol.
//! This library contains various backends to communicate over different networks (eg. serial in RTU mode or Ethernet in TCP/IPv6).
//! The http://www.modbus.org site provides documentation about the protocol at http://www.modbus.org/specs.php.
//!
//! libmodbus provides an abstraction of the lower communication layers and offers the same API on all supported platforms.
//!
//! This documentation presents an overview of libmodbus concepts, describes how libmodbus abstracts Modbus communication with
//! different hardware and platforms and provides a reference manual for the functions provided by the libmodbus library.
//!
//! ## Contexts
//!
//! The Modbus protocol contains many variants (eg. serial RTU or Ehternet TCP), to ease the implementation of a variant,
//! the library was designed to use a backend for each variant.
//! The backends are also a convenient way to fulfill other requirements (eg. real-time operations). Each backend offers a specific function to create a new modbus_t context.
//! The modbus_t context is an opaque structure containing all necessary information to establish a connection with others Modbus devices according to the selected variant.
//!
//! You can choose the best context for your needs among:
//!
//! * [RTU Context](trait.ModbusRTU.html)
//! * [TCP (IPv4) Context](trait.ModbusTCP.html)
//! * [TCP PI (IPv4 and IPv6) Context](trait.ModbusTCPPI.html)
//!
//! ### [RTU Context](trait.ModbusRTU.html)
//!
//! The RTU backend (Remote Terminal Unit) is used in serial communication and makes use of a compact, binary representation of the data for protocol communication.
//! The RTU format follows the commands/data with a cyclic redundancy check checksum as an error check mechanism to ensure the reliability of data.
//! Modbus RTU is the most common implementation available for Modbus. A Modbus RTU message must be transmitted continuously without inter-character hesitations
//! (extract from Wikipedia, Modbus, http://en.wikipedia.org/wiki/Modbus (as of Mar. 13, 2011, 20:51 GMT).
//!
//! The Modbus RTU framing calls a slave, a device/service which handle Modbus requests, and a master, a client which send requests. The communication is always initiated by the master.
//!
//! Many Modbus devices can be connected together on the same physical link so before sending a message, you must set the slave (receiver) with modbus_set_slave(3).
//! If you’re running a slave, its slave number will be used to filter received messages.
//!
//! The libmodbus implementation of RTU isn’t time based as stated in original Modbus specification,
//! instead all bytes are sent as fast as possible and a response or an indication is considered complete when all expected characters have been received.
//! This implementation offers very fast communication but you must take care to set a response timeout of slaves less than response timeout of master
//! (ortherwise other slaves may ignore master requests when one of the slave is not responding).
//!
//! * Create a Modbus RTU context
//!     - [`new_rtu()`](struct.Modbus.html#method.new_rtu)
//!
//! * Set the serial mode
//!     - [`rtu_get_serial_mode()`](struct.Modbus.html#method.rtu_get_serial_mode), [`rtu_set_serial_mode()`](struct.Modbus.html#method.rtu_set_serial_mode), [`rtu_get_rts()`](struct.Modbus.html#method.rtu_get_rts), [`rtu_set_rts()`](struct.Modbus.html#method.rtu_set_rts), [`rtu_set_custom_rts()`](struct.Modbus.html#method.rtu_set_custom_rts), [`rtu_get_rts_delay()`](struct.Modbus.html#method.rtu_get_rts_delay), [`rtu_set_rts_delay()`](struct.Modbus.html#method.rtu_set_rts_delay)
//!
//! ### [TCP (IPv4) Context](trait.ModbusTCP.html)
//! The TCP backend implements a Modbus variant used for communications over TCP/IPv4 networks.
//! It does not require a checksum calculation as lower layer takes care of the same.
//!
//! * Create a Modbus TCP context
//!     - [`new_tcp()`](struct.Modbus.html#method.new_tcp)
//!
//! ### [TCP PI (IPv4 and IPv6) Context](trait.ModbusTCPPI.html)
//! The TCP PI (Protocol Independent) backend implements a Modbus variant used for communications over TCP IPv4 and IPv6 networks.
//! It does not require a checksum calculation as lower layer takes care of the same.
//!
//! Contrary to the TCP IPv4 only backend, the TCP PI backend offers hostname resolution but it consumes about 1Kb of additional memory.
//!
//! * Create a Modbus TCP context
//!     - [`new_tcp_pi()`](struct.Modbus.html#method.new_tcp_pi)
//!
//! ### Common
//!
//! ### Connection
//!
//! ### [`Client`](trait.ModbusClient.html)
//!
//! The Modbus protocol defines different data types and functions to read and write them from/to remote devices.
//! The following functions are used by the clients to send Modbus requests:
//!
//! * Read data
//!     - [`read_bits()`](struct.Modbus.html#method.read_bitsmode), [`read_input_bits()`](struct.Modbus.html#method.read_input_bits), [`read_registers()`](struct.Modbus.html#method.read_registers), [`read_input_registers()`](struct.Modbus.html#method.read_input_registers), [`report_slave_id()`](struct.Modbus.html#method.report_slave_id)
//! * Write data
//!     - [`write_bit()`](struct.Modbus.html#method.write_bit), [`write_register()`](struct.Modbus.html#method.write_register), [`write_bits()`](struct.Modbus.html#method.write_bits), [`write_registers()`](struct.Modbus.html#method.write_registers)
//! * Write and read data
//!     - [`write_and_read_registers()`](struct.Modbus.html#method.write_and_read_registers)
//! * Raw requests
//!     - [`send_raw_request()`](struct.Modbus.html#method.send_raw_request), [`receive_confirmation()`](struct.Modbus.html#method.receive_confirmation)
//! * Reply an exception
//!     - [`reply_exception()`](struct.Modbus.html#method.reply_exception)
//!
//! ### [`Server`](trait.ModbusServer.html)
//!
//! The server is waiting for request from clients and must answer when it is concerned by the request. The libmodbus offers the following functions to handle requests:
//!
//! * Receive
//!     - [`receive()`](struct.Modbus.html#method.receive)
//! * Reply
//!     - [`reply()`](struct.Modbus.html#method.reply), [`reply_exception()`](struct.Modbus.html#method.reply_exception)
//!

// `error_chain!` can recurse deeply(3)
#![recursion_limit = "1024"]

extern crate libc;
extern crate libmodbus_sys;
#[macro_use] extern crate error_chain;

pub mod errors;
mod modbus_client;
mod modbus_rtu;
mod modbus_server;
mod modbus_tcp_pi;
mod modbus_tcp;
mod modbus;

pub use self::modbus_client::ModbusClient;
pub use self::modbus_rtu::{ModbusRTU, request_to_send_mode, serial_mode};
pub use self::modbus_server::ModbusServer;
pub use self::modbus_tcp_pi::ModbusTCPPI;
pub use self::modbus_tcp::ModbusTCP;
pub use self::modbus::Modbus;

pub use libmodbus_sys::MODBUS_TCP_DEFAULT_PORT;
pub use libmodbus_sys::MODBUS_MAX_ADU_LENGTH;
<|endoftext|>


<commit_before>#![deny(warnings)]
#![recursion_limit = "1024"]
#[macro_use]
extern crate enum_primitive_derive;
use num_traits::ToPrimitive;

use async_trait::async_trait;
use futures::channel::{mpsc, oneshot};
use std::convert::TryFrom;
use std::fmt::{Debug, Display};
use std::net::SocketAddr;
use tokio_util::codec::Framed;

mod codec;
mod dealer_router;
mod error;
mod fair_queue;
mod message;
mod r#pub;
mod rep;
mod req;
mod sub;
pub mod util;

#[cfg(test)]
mod tests;

use crate::codec::*;
pub use crate::dealer_router::*;
pub use crate::error::ZmqError;
pub use crate::r#pub::*;
pub use crate::rep::*;
pub use crate::req::*;
pub use crate::sub::*;
use crate::util::*;
pub use message::*;

pub type ZmqResult<T> = Result<T, ZmqError>;

#[derive(Clone, Copy, Debug, PartialEq, Primitive)]
pub enum SocketType {
    PAIR = 0,
    PUB = 1,
    SUB = 2,
    REQ = 3,
    REP = 4,
    DEALER = 5,
    ROUTER = 6,
    PULL = 7,
    PUSH = 8,
    XPUB = 9,
    XSUB = 10,
    STREAM = 11,
}

impl TryFrom<&str> for SocketType {
    type Error = ZmqError;

    fn try_from(s: &str) -> Result<Self, ZmqError> {
        Ok(match s {
            "PAIR" => SocketType::PAIR,
            "PUB" => SocketType::PUB,
            "SUB" => SocketType::SUB,
            "REQ" => SocketType::REQ,
            "REP" => SocketType::REP,
            "DEALER" => SocketType::DEALER,
            "ROUTER" => SocketType::ROUTER,
            "PULL" => SocketType::PULL,
            "PUSH" => SocketType::PUSH,
            "XPUB" => SocketType::XPUB,
            "XSUB" => SocketType::XSUB,
            "STREAM" => SocketType::STREAM,
            _ => return Err(ZmqError::Codec("Unknown socket type")),
        })
    }
}

impl Display for SocketType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            SocketType::PAIR => write!(f, "PAIR"),
            SocketType::PUB => write!(f, "PUB"),
            SocketType::SUB => write!(f, "SUB"),
            SocketType::REQ => write!(f, "REQ"),
            SocketType::REP => write!(f, "REP"),
            SocketType::DEALER => write!(f, "DEALER"),
            SocketType::ROUTER => write!(f, "ROUTER"),
            SocketType::PULL => write!(f, "PULL"),
            SocketType::PUSH => write!(f, "PUSH"),
            SocketType::XPUB => write!(f, "XPUB"),
            SocketType::XSUB => write!(f, "XSUB"),
            SocketType::STREAM => write!(f, "STREAM"),
        }
    }
}

#[async_trait]
trait MultiPeer: SocketBackend {
    async fn peer_connected(
        &self,
        peer_id: &PeerIdentity,
    ) -> (mpsc::Receiver<Message>, oneshot::Receiver<bool>);
    async fn peer_disconnected(&self, peer_id: &PeerIdentity);
}

#[async_trait]
trait SocketBackend: Send + Sync {
    async fn message_received(&self, peer_id: &PeerIdentity, message: Message);

    fn socket_type(&self) -> SocketType;
    fn shutdown(&self);
}

#[async_trait]
pub trait BlockingRecv {
    async fn recv(&mut self) -> ZmqResult<ZmqMessage>;
}

#[async_trait]
pub trait BlockingSend {
    async fn send(&mut self, message: ZmqMessage) -> ZmqResult<()>;
}

pub trait NonBlockingSend {
    fn send(&mut self, message: ZmqMessage) -> ZmqResult<()>;
}

pub trait NonBlockingRecv {
    fn recv(&mut self) -> ZmqResult<ZmqMessage>;
}

#[async_trait]
pub trait Socket {
    fn new() -> Self;

    /// Opens port described by endpoint and starts a coroutine to accept new connections on it
    async fn bind(&mut self, endpoint: &str) -> ZmqResult<()>;
    async fn connect(&mut self, endpoint: &str) -> ZmqResult<()>;
}
<commit_msg>Added prelude module<commit_after>#![deny(warnings)]
#![recursion_limit = "1024"]
#[macro_use]
extern crate enum_primitive_derive;
use num_traits::ToPrimitive;

use async_trait::async_trait;
use futures::channel::{mpsc, oneshot};
use std::convert::TryFrom;
use std::fmt::{Debug, Display};
use std::net::SocketAddr;
use tokio_util::codec::Framed;

mod codec;
mod dealer_router;
mod error;
mod fair_queue;
mod message;
mod r#pub;
mod rep;
mod req;
mod sub;
pub mod util;

#[cfg(test)]
mod tests;

use crate::codec::*;
pub use crate::dealer_router::*;
pub use crate::error::ZmqError;
pub use crate::r#pub::*;
pub use crate::rep::*;
pub use crate::req::*;
pub use crate::sub::*;
use crate::util::*;
pub use message::*;

pub type ZmqResult<T> = Result<T, ZmqError>;

#[derive(Clone, Copy, Debug, PartialEq, Primitive)]
pub enum SocketType {
    PAIR = 0,
    PUB = 1,
    SUB = 2,
    REQ = 3,
    REP = 4,
    DEALER = 5,
    ROUTER = 6,
    PULL = 7,
    PUSH = 8,
    XPUB = 9,
    XSUB = 10,
    STREAM = 11,
}

impl TryFrom<&str> for SocketType {
    type Error = ZmqError;

    fn try_from(s: &str) -> Result<Self, ZmqError> {
        Ok(match s {
            "PAIR" => SocketType::PAIR,
            "PUB" => SocketType::PUB,
            "SUB" => SocketType::SUB,
            "REQ" => SocketType::REQ,
            "REP" => SocketType::REP,
            "DEALER" => SocketType::DEALER,
            "ROUTER" => SocketType::ROUTER,
            "PULL" => SocketType::PULL,
            "PUSH" => SocketType::PUSH,
            "XPUB" => SocketType::XPUB,
            "XSUB" => SocketType::XSUB,
            "STREAM" => SocketType::STREAM,
            _ => return Err(ZmqError::Codec("Unknown socket type")),
        })
    }
}

impl Display for SocketType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            SocketType::PAIR => write!(f, "PAIR"),
            SocketType::PUB => write!(f, "PUB"),
            SocketType::SUB => write!(f, "SUB"),
            SocketType::REQ => write!(f, "REQ"),
            SocketType::REP => write!(f, "REP"),
            SocketType::DEALER => write!(f, "DEALER"),
            SocketType::ROUTER => write!(f, "ROUTER"),
            SocketType::PULL => write!(f, "PULL"),
            SocketType::PUSH => write!(f, "PUSH"),
            SocketType::XPUB => write!(f, "XPUB"),
            SocketType::XSUB => write!(f, "XSUB"),
            SocketType::STREAM => write!(f, "STREAM"),
        }
    }
}

#[async_trait]
trait MultiPeer: SocketBackend {
    async fn peer_connected(
        &self,
        peer_id: &PeerIdentity,
    ) -> (mpsc::Receiver<Message>, oneshot::Receiver<bool>);
    async fn peer_disconnected(&self, peer_id: &PeerIdentity);
}

#[async_trait]
trait SocketBackend: Send + Sync {
    async fn message_received(&self, peer_id: &PeerIdentity, message: Message);

    fn socket_type(&self) -> SocketType;
    fn shutdown(&self);
}

#[async_trait]
pub trait BlockingRecv {
    async fn recv(&mut self) -> ZmqResult<ZmqMessage>;
}

#[async_trait]
pub trait BlockingSend {
    async fn send(&mut self, message: ZmqMessage) -> ZmqResult<()>;
}

pub trait NonBlockingSend {
    fn send(&mut self, message: ZmqMessage) -> ZmqResult<()>;
}

pub trait NonBlockingRecv {
    fn recv(&mut self) -> ZmqResult<ZmqMessage>;
}

#[async_trait]
pub trait Socket {
    fn new() -> Self;

    /// Opens port described by endpoint and starts a coroutine to accept new connections on it
    async fn bind(&mut self, endpoint: &str) -> ZmqResult<()>;
    async fn connect(&mut self, endpoint: &str) -> ZmqResult<()>;
}

pub mod prelude {
    //! Re-exports important traits. Consider glob-importing.

    pub use crate::{BlockingRecv, BlockingSend, NonBlockingRecv, NonBlockingSend, Socket};
}
<|endoftext|>