<commit_before>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use futures::{future, unsync, Future, IntoFuture, Sink, Stream};
use futures::future::Either;
use futures::sync::mpsc;
use tokio_core::net::{TcpListener, TcpStream, TcpStreamNew};
use tokio_core::reactor::Handle;
use tokio_io::AsyncRead;
use tokio_retry::{Action, Retry};
use tokio_retry::strategy::{jitter, FixedInterval};

use std::net::SocketAddr;
use std::time::Duration;
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;

use messages::{Any, Connect, RawMessage};
use node::{ExternalMessage, NodeTimeout};
use helpers::Milliseconds;

use super::error::{into_other, log_error, other_error, result_ok};
use super::codec::MessagesCodec;
use super::{EventsAggregator, EventHandler};

#[derive(Debug)]
pub enum NetworkEvent {
    MessageReceived(SocketAddr, RawMessage),
    PeerConnected(SocketAddr, Connect),
    PeerDisconnected(SocketAddr),
}

#[derive(Debug, Clone)]
pub enum NetworkRequest {
    SendMessage(SocketAddr, RawMessage),
    DisconnectWithPeer(SocketAddr),
    Shutdown,
}

#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct NetworkConfiguration {
    // TODO: think more about config parameters
    pub max_incoming_connections: usize,
    pub max_outgoing_connections: usize,
    pub tcp_nodelay: bool,
    pub tcp_keep_alive: Option<u64>,
    pub tcp_connect_retry_timeout: Milliseconds,
    pub tcp_connect_max_retries: u64,
}

impl Default for NetworkConfiguration {
    fn default() -> NetworkConfiguration {
        NetworkConfiguration {
            max_incoming_connections: 128,
            max_outgoing_connections: 128,
            tcp_keep_alive: None,
            tcp_nodelay: false,
            tcp_connect_retry_timeout: 15_000,
            tcp_connect_max_retries: 10,
        }
    }
}

#[derive(Debug)]
pub struct HandlerPart<H: EventHandler> {
    pub handler: H,
    pub timeout_rx: mpsc::Receiver<NodeTimeout>,
    pub network_rx: mpsc::Receiver<NetworkEvent>,
    pub api_rx: mpsc::Receiver<ExternalMessage>,
}

#[derive(Debug)]
pub struct NetworkPart {
    pub listen_address: SocketAddr,
    pub network_config: NetworkConfiguration,
    pub network_requests: (mpsc::Sender<NetworkRequest>, mpsc::Receiver<NetworkRequest>),
    pub network_tx: mpsc::Sender<NetworkEvent>,
}

#[derive(Debug, Default, Clone)]
struct ConnectionsPool {
    inner: Rc<RefCell<HashMap<SocketAddr, mpsc::Sender<RawMessage>>>>,
}

impl ConnectionsPool {
    fn new() -> ConnectionsPool {
        ConnectionsPool::default()
    }

    fn insert(&self, peer: SocketAddr, sender: &mpsc::Sender<RawMessage>) {
        self.inner.borrow_mut().insert(peer, sender.clone());
    }

    fn remove(&self, peer: &SocketAddr) {
        self.inner.borrow_mut().remove(peer);
    }

    fn get(&self, peer: SocketAddr) -> Option<mpsc::Sender<RawMessage>> {
        self.inner.borrow_mut().get(&peer).cloned()
    }

    fn len(&self) -> usize {
        self.inner.borrow_mut().len()
    }
}

impl<H: EventHandler + 'static> HandlerPart<H> {
    pub fn run(self) -> Box<Future<Item=(), Error=()>> {
        let mut handler = self.handler;

        let fut = EventsAggregator::new(self.timeout_rx, self.network_rx, self.api_rx)
            .for_each(move |event| {
                handler.handle_event(event);
                Ok(())
            });

        Box::new(fut)
    }
}

impl NetworkPart {
    pub fn run(self, handle_orig: Handle) -> Box<Future<Item=(), Error=()>> {
        let network_config = self.network_config;
        // Cancelation token
        let (cancel_sender, cancel_handler) = unsync::oneshot::channel();
        let mut cancel_sender = Some(cancel_sender);
        // Outgoing connections
        let outgoing_connections = ConnectionsPool::new();
        let network_tx = self.network_tx.clone();
        // Outgoing connections limiter
        let outgoing_connections_limit = network_config.max_outgoing_connections;
        let handle = handle_orig.clone();
        let requests_handle = self.network_requests.1.for_each(move |request| {
            let handle = handle.clone();
            let network_tx = network_tx.clone();
            let outgoing_connections = outgoing_connections.clone();
            match request {
                NetworkRequest::SendMessage(peer, msg) => {
                    let conn_tx =
                        if let Some(conn_tx) = outgoing_connections.get(peer) {
                            conn_tx
                        } else {
                            // Check limit
                            if outgoing_connections.len() >= outgoing_connections_limit {
                                warn!(
                                    "Rejected outgoing connection with peer={}, \
                                     connections limit reached.",
                                    peer
                                );
                                let event = NetworkEvent::PeerDisconnected(peer);
                                handle.spawn(network_tx.clone().send(event).map(drop).map_err(log_error));
                            }
                            // Register outgoing channel.
                            let (conn_tx, conn_rx) = mpsc::channel(10);
                            outgoing_connections.insert(peer, &conn_tx);
                            // Enable retry feature for outgoing connection.
                            let timeout = network_config.tcp_connect_retry_timeout;
                            let max_tries = network_config.tcp_connect_max_retries as usize;
                            let connect_handle = Retry::spawn(
                                handle.clone(),
                                FixedInterval::from_millis(timeout).map(jitter).take(
                                    max_tries,
                                ),
                                TcpStreamConnectAction {
                                    handle: handle.clone(),
                                    peer,
                                },
                            ).map_err(into_other)
                                // Configure socket
                                .and_then(move |sock| {
                                    sock.set_nodelay(network_config.tcp_nodelay)?;
                                    Ok(sock)
                                })
                                .and_then(move |sock| {
                                    let duration =
                                        network_config.tcp_keep_alive.map(Duration::from_millis);
                                    sock.set_keepalive(duration)?;
                                    Ok(sock)
                                })
                                // Connect socket with the outgoing channel
                                .and_then(move |sock| {
                                    trace!("Established connection with peer={}", peer);

                                    let stream = sock.framed(MessagesCodec);
                                    let (sink, stream) = stream.split();

                                    let writer = conn_rx
                                        .map_err(|_| other_error("Can't send data into socket"))
                                        .forward(sink);
                                    let reader = stream.for_each(result_ok);

                                    reader
                                        .select2(writer)
                                        .map_err(|_| other_error("Socket error"))
                                        .and_then(|res| match res {
                                            Either::A((_, _reader)) => Ok(()).into_future(),
                                            Either::B((_, _writer)) => Ok(()).into_future(),
                                        })
                                })
                                .then(move |res| {
                                    trace!("Connection with peer={} closed, reason={:?}", peer, res);
                                    outgoing_connections.clone().remove(&peer);
                                    network_tx
                                        .clone()
                                        .send(NetworkEvent::PeerDisconnected(peer))
                                        .map(drop)
                                })
                                .map_err(log_error);
                            handle.spawn(connect_handle);
                            conn_tx
                        };

                    let send_handle = conn_tx.send(msg).map_err(log_error).map(drop);
                    tobox(send_handle)
                }
                NetworkRequest::DisconnectWithPeer(peer) => {
                    outgoing_connections.remove(&peer);
                    let event = NetworkEvent::PeerDisconnected(peer);
                    let fut = network_tx.clone().send(event).map(drop).map_err(log_error);
                    tobox(fut)
                }
                // Immediately stop the event loop.
                NetworkRequest::Shutdown => {
                    let fut = cancel_sender
                        .take()
                        .ok_or_else(|| other_error("Shutdown twice"))
                        .and_then(|sender| {
                            sender.send(()).map_err(
                                |_| other_error("Can't send shutdown signal"),
                            )
                        })
                        .map_err(log_error)
                        .into_future();
                    tobox(fut)
                }
            }
        });

        // Incoming connections limiter
        let incoming_connections_limit = network_config.max_incoming_connections;
        let incoming_connections_counter: Rc<()> = Rc::default();
        // Incoming connections handler
        // TODO Don't use unwrap here!
        let listener = TcpListener::bind(&self.listen_address, &handle_orig).unwrap();
        let network_tx = self.network_tx.clone();
        let server = listener
            .incoming()
            .for_each(move |(sock, addr)| {
                // Increment reference counter
                let holder = Rc::downgrade(&incoming_connections_counter);
                // Check incoming connections count
                let connections_count = Rc::weak_count(&incoming_connections_counter);
                if connections_count > incoming_connections_limit {
                    warn!(
                        "Rejected incoming connection with peer={}, \
                         connections limit reached.",
                        addr
                    );
                    tobox(future::ok(()))
                } else {
                    trace!("Accepted incoming connection with peer={}", addr);
                    let stream = sock.framed(MessagesCodec);
                    let (_, stream) = stream.split();
                    let network_tx = network_tx.clone();
                    let connection_handler = stream
                        .into_future()
                        .map_err(|e| e.0)
                        .and_then(move |(raw, stream)| match raw.map(Any::from_raw) {
                            Some(Ok(Any::Connect(msg))) => Ok((msg, stream)),
                            Some(Ok(other)) => Err(other_error(&format!(
                                "First message is not Connect, got={:?}",
                                other
                            ))),
                            Some(Err(e)) => Err(into_other(e)),
                            None => Err(other_error("Incoming socket closed")),
                        })
                        .and_then(move |(connect, stream)| {
                            trace!("Received handshake message={:?}", connect);
                            let event = NetworkEvent::PeerConnected(addr, connect);
                            let stream = network_tx
                                .clone()
                                .send(event)
                                .map_err(into_other)
                                .and_then(move |_| Ok(stream))
                                .flatten_stream();

                            stream.for_each(move |raw| {
                                let event = NetworkEvent::MessageReceived(addr, raw);
                                network_tx.clone().send(event).map_err(into_other).map(drop)
                            })
                        })
                        .map(|_| {
                            // Ensure that holder lives until the stream ends.
                            let _holder = holder;
                        });
                    tobox(connection_handler)
                }
            })
            .map_err(log_error);

        let cancel_handler = cancel_handler.map_err(drop);
        let tasks = vec![
            tobox(server),
            tobox(requests_handle),
            tobox(cancel_handler)
        ];
        tobox(future::join_all(tasks))
    }
}

fn tobox<F: Future + 'static>(f: F) -> Box<Future<Item=(), Error=F::Error>> {
    let fut = f.map(|_| ());
    Box::new(fut)
}

// Tcp streams source for retry action.
struct TcpStreamConnectAction {
    handle: Handle,
    peer: SocketAddr,
}

impl Action for TcpStreamConnectAction {
    type Future = TcpStreamNew;
    type Item = <TcpStreamNew as Future>::Item;
    type Error = <TcpStreamNew as Future>::Error;

    fn run(&mut self) -> Self::Future {
        TcpStream::connect(&self.peer, &self.handle)
    }
}
<commit_msg>Use closure instead of action for NetworkPart<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use futures::{future, unsync, Future, IntoFuture, Sink, Stream};
use futures::future::Either;
use futures::sync::mpsc;
use tokio_core::net::{TcpListener, TcpStream};
use tokio_core::reactor::Handle;
use tokio_io::AsyncRead;
use tokio_retry::Retry;
use tokio_retry::strategy::{jitter, FixedInterval};

use std::net::SocketAddr;
use std::time::Duration;
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;

use messages::{Any, Connect, RawMessage};
use node::{ExternalMessage, NodeTimeout};
use helpers::Milliseconds;

use super::error::{into_other, log_error, other_error, result_ok};
use super::codec::MessagesCodec;
use super::{EventsAggregator, EventHandler};

#[derive(Debug)]
pub enum NetworkEvent {
    MessageReceived(SocketAddr, RawMessage),
    PeerConnected(SocketAddr, Connect),
    PeerDisconnected(SocketAddr),
}

#[derive(Debug, Clone)]
pub enum NetworkRequest {
    SendMessage(SocketAddr, RawMessage),
    DisconnectWithPeer(SocketAddr),
    Shutdown,
}

#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct NetworkConfiguration {
    // TODO: think more about config parameters
    pub max_incoming_connections: usize,
    pub max_outgoing_connections: usize,
    pub tcp_nodelay: bool,
    pub tcp_keep_alive: Option<u64>,
    pub tcp_connect_retry_timeout: Milliseconds,
    pub tcp_connect_max_retries: u64,
}

impl Default for NetworkConfiguration {
    fn default() -> NetworkConfiguration {
        NetworkConfiguration {
            max_incoming_connections: 128,
            max_outgoing_connections: 128,
            tcp_keep_alive: None,
            tcp_nodelay: false,
            tcp_connect_retry_timeout: 15_000,
            tcp_connect_max_retries: 10,
        }
    }
}

#[derive(Debug)]
pub struct HandlerPart<H: EventHandler> {
    pub handler: H,
    pub timeout_rx: mpsc::Receiver<NodeTimeout>,
    pub network_rx: mpsc::Receiver<NetworkEvent>,
    pub api_rx: mpsc::Receiver<ExternalMessage>,
}

#[derive(Debug)]
pub struct NetworkPart {
    pub listen_address: SocketAddr,
    pub network_config: NetworkConfiguration,
    pub network_requests: (mpsc::Sender<NetworkRequest>, mpsc::Receiver<NetworkRequest>),
    pub network_tx: mpsc::Sender<NetworkEvent>,
}

#[derive(Debug, Default, Clone)]
struct ConnectionsPool {
    inner: Rc<RefCell<HashMap<SocketAddr, mpsc::Sender<RawMessage>>>>,
}

impl ConnectionsPool {
    fn new() -> ConnectionsPool {
        ConnectionsPool::default()
    }

    fn insert(&self, peer: SocketAddr, sender: &mpsc::Sender<RawMessage>) {
        self.inner.borrow_mut().insert(peer, sender.clone());
    }

    fn remove(&self, peer: &SocketAddr) {
        self.inner.borrow_mut().remove(peer);
    }

    fn get(&self, peer: SocketAddr) -> Option<mpsc::Sender<RawMessage>> {
        self.inner.borrow_mut().get(&peer).cloned()
    }

    fn len(&self) -> usize {
        self.inner.borrow_mut().len()
    }
}

impl<H: EventHandler + 'static> HandlerPart<H> {
    pub fn run(self) -> Box<Future<Item=(), Error=()>> {
        let mut handler = self.handler;

        let fut = EventsAggregator::new(self.timeout_rx, self.network_rx, self.api_rx)
            .for_each(move |event| {
                handler.handle_event(event);
                Ok(())
            });

        Box::new(fut)
    }
}

impl NetworkPart {
    pub fn run(self, handle_orig: Handle) -> Box<Future<Item=(), Error=()>> {
        let network_config = self.network_config;
        // Cancelation token
        let (cancel_sender, cancel_handler) = unsync::oneshot::channel();
        let mut cancel_sender = Some(cancel_sender);
        // Outgoing connections
        let outgoing_connections = ConnectionsPool::new();
        let network_tx = self.network_tx.clone();
        // Outgoing connections limiter
        let outgoing_connections_limit = network_config.max_outgoing_connections;
        let handle = handle_orig.clone();
        let requests_handle = self.network_requests.1.for_each(move |request| {
            let handle = handle.clone();
            let network_tx = network_tx.clone();
            let outgoing_connections = outgoing_connections.clone();
            match request {
                NetworkRequest::SendMessage(peer, msg) => {
                    let conn_tx =
                        if let Some(conn_tx) = outgoing_connections.get(peer) {
                            conn_tx
                        } else {
                            // Check limit
                            if outgoing_connections.len() >= outgoing_connections_limit {
                                warn!(
                                    "Rejected outgoing connection with peer={}, \
                                     connections limit reached.",
                                    peer
                                );
                                let event = NetworkEvent::PeerDisconnected(peer);
                                handle.spawn(network_tx.clone().send(event).map(drop).map_err(log_error));
                            }
                            // Register outgoing channel.
                            let (conn_tx, conn_rx) = mpsc::channel(10);
                            outgoing_connections.insert(peer, &conn_tx);
                            // Enable retry feature for outgoing connection.
                            let timeout = network_config.tcp_connect_retry_timeout;
                            let max_tries = network_config.tcp_connect_max_retries as usize;
                            let strategy = FixedInterval::from_millis(timeout)
                                .map(jitter)
                                .take(max_tries);
                            let handle_cloned = handle.clone();
                            let action = move || {
                                TcpStream::connect(&peer, &handle_cloned)
                            };
                            let connect_handle = Retry::spawn(handle.clone(), strategy, action)
                                .map_err(into_other)
                                // Configure socket
                                .and_then(move |sock| {
                                    sock.set_nodelay(network_config.tcp_nodelay)?;
                                    let duration =
                                        network_config.tcp_keep_alive.map(Duration::from_millis);
                                    sock.set_keepalive(duration)?;
                                    Ok(sock)
                                })
                                // Connect socket with the outgoing channel
                                .and_then(move |sock| {
                                    trace!("Established connection with peer={}", peer);

                                    let stream = sock.framed(MessagesCodec);
                                    let (sink, stream) = stream.split();

                                    let writer = conn_rx
                                        .map_err(|_| other_error("Can't send data into socket"))
                                        .forward(sink);
                                    let reader = stream.for_each(result_ok);

                                    reader
                                        .select2(writer)
                                        .map_err(|_| other_error("Socket error"))
                                        .and_then(|res| match res {
                                            Either::A((_, _reader)) => Ok("by reader"),
                                            Either::B((_, _writer)) => Ok("by writer"),
                                        })
                                })
                                .then(move |res| {
                                    trace!("Connection with peer={} closed, reason={:?}", peer, res);
                                    outgoing_connections.clone().remove(&peer);
                                    network_tx
                                        .clone()
                                        .send(NetworkEvent::PeerDisconnected(peer))
                                        .map(drop)
                                })
                                .map_err(log_error);
                            handle.spawn(connect_handle);
                            conn_tx
                        };

                    let send_handle = conn_tx.send(msg).map_err(log_error).map(drop);
                    tobox(send_handle)
                }
                NetworkRequest::DisconnectWithPeer(peer) => {
                    outgoing_connections.remove(&peer);
                    let event = NetworkEvent::PeerDisconnected(peer);
                    let fut = network_tx.clone().send(event).map(drop).map_err(log_error);
                    tobox(fut)
                }
                // Immediately stop the event loop.
                NetworkRequest::Shutdown => {
                    let fut = cancel_sender
                        .take()
                        .ok_or_else(|| other_error("Shutdown twice"))
                        .and_then(|sender| {
                            sender.send(()).map_err(
                                |_| other_error("Can't send shutdown signal"),
                            )
                        })
                        .map_err(log_error)
                        .into_future();
                    tobox(fut)
                }
            }
        });

        // Incoming connections limiter
        let incoming_connections_limit = network_config.max_incoming_connections;
        let incoming_connections_counter: Rc<()> = Rc::default();
        // Incoming connections handler
        // TODO Don't use unwrap here!
        let listener = TcpListener::bind(&self.listen_address, &handle_orig).unwrap();
        let network_tx = self.network_tx.clone();
        let server = listener
            .incoming()
            .for_each(move |(sock, addr)| {
                // Increment reference counter
                let holder = Rc::downgrade(&incoming_connections_counter);
                // Check incoming connections count
                let connections_count = Rc::weak_count(&incoming_connections_counter);
                if connections_count > incoming_connections_limit {
                    warn!(
                        "Rejected incoming connection with peer={}, \
                         connections limit reached.",
                        addr
                    );
                    tobox(future::ok(()))
                } else {
                    trace!("Accepted incoming connection with peer={}", addr);
                    let stream = sock.framed(MessagesCodec);
                    let (_, stream) = stream.split();
                    let network_tx = network_tx.clone();
                    let connection_handler = stream
                        .into_future()
                        .map_err(|e| e.0)
                        .and_then(move |(raw, stream)| match raw.map(Any::from_raw) {
                            Some(Ok(Any::Connect(msg))) => Ok((msg, stream)),
                            Some(Ok(other)) => Err(other_error(&format!(
                                "First message is not Connect, got={:?}",
                                other
                            ))),
                            Some(Err(e)) => Err(into_other(e)),
                            None => Err(other_error("Incoming socket closed")),
                        })
                        .and_then(move |(connect, stream)| {
                            trace!("Received handshake message={:?}", connect);
                            let event = NetworkEvent::PeerConnected(addr, connect);
                            let stream = network_tx
                                .clone()
                                .send(event)
                                .map_err(into_other)
                                .and_then(move |_| Ok(stream))
                                .flatten_stream();

                            stream.for_each(move |raw| {
                                let event = NetworkEvent::MessageReceived(addr, raw);
                                network_tx.clone().send(event).map_err(into_other).map(drop)
                            })
                        })
                        .map(|_| {
                            // Ensure that holder lives until the stream ends.
                            let _holder = holder;
                        });
                    tobox(connection_handler)
                }
            })
            .map_err(log_error);

        let cancel_handler = cancel_handler.map_err(drop);
        let tasks = vec![
            tobox(server),
            tobox(requests_handle),
            tobox(cancel_handler)
        ];
        tobox(future::join_all(tasks))
    }
}

fn tobox<F: Future + 'static>(f: F) -> Box<Future<Item=(), Error=F::Error>> {
    let fut = f.map(|_| ());
    Box::new(fut)
}

<|endoftext|>


<commit_before>
#![feature(phase)]

#[phase(plugin, link)]
extern crate conrod;
extern crate graphics;
extern crate piston;
extern crate sdl2_game_window;
extern crate opengl_graphics;

use sdl2_game_window::GameWindowSDL2;
use opengl_graphics::Gl;
use piston::{
    Game,
    GameEvent,
    GameWindowSettings,
    GameIterator,
    GameIteratorSettings,
    RenderArgs,
    Render,
};
use conrod::{
    button,
    label,
    number_dialer,
    slider,
    toggle,
    widget_matrix,
    Color,
    Point,
    Frame,
    UIContext,
};
use conrod::label::{
    Label,
    NoLabel,
};
use graphics::{
    Context,
    AddColor,
    Draw,
};

fn main() {

    // Create a SDL2 window.
    let mut window = GameWindowSDL2::new(
        GameWindowSettings {
            title: "Hello Conrod".to_string(),
            size: [600, 600],
            fullscreen: false,
            exit_on_esc: true
        }
    );

    // Some settings for how the game should be run.
    let game_iter_settings = GameIteratorSettings {
        updates_per_second: 180,
        max_frames_per_second: 60
    };

    // Create GameIterator to begin the event iteration loop.
    let mut game_iter = GameIterator::new(&mut window, &game_iter_settings);
    // Create OpenGL instance.
    let mut gl = Gl::new();
    // Create the UIContext and specify the name of a font that's in our "assets" directory.
    let mut uic = UIContext::new("Dense-Regular.otf");

    // TODO: Put the following vars all in an 'app' struct or something and pass
    // as a mut reference to struct instead.

    // Background color (for demonstration of button and sliders).
    let mut bg_color = Color::new(0.2, 0.35, 0.45, 1.0);
    // Should the button be shown (for demonstration of button).
    let mut show_button = false;
    // The label that will be drawn to the Toggle.
    let mut toggle_label = "OFF".to_string();
    // The number of pixels between the left side of the window and the title.
    let mut title_padding = 50f64;
    // The height of the vertical sliders (we will play with this using a number_dialer).
    let mut v_slider_height = 185f64;
    // The widget frame width (we'll use this to demo Framing and number_dialer).
    let mut frame_width = 6f64;
    // Bool matrix for widget_matrix demonstration.
    let mut bool_matrix = vec![
                            vec![true, true, true, true, true, true, true, true],
                            vec![true, true, true, true, true, true, true, true],
                            vec![true, true, true, true, true, true, true, true],
                            vec![true, true, true, true, true, true, true, true],
                            vec![true, true, true, true, true, true, true, true],
                            vec![true, true, true, true, true, true, true, true],
                            vec![true, true, true, true, true, true, true, true],
                            vec![true, true, true, true, true, true, true, true],
                            ];

    // Main program loop begins.
    loop {
        match game_iter.next() {
            None => break,
            Some(mut e) => handle_event(&mut e,
                                        &mut gl,
                                        &mut uic,
                                        &mut bg_color,
                                        &mut show_button,
                                        &mut toggle_label,
                                        &mut title_padding,
                                        &mut v_slider_height,
                                        &mut frame_width,
                                        &mut bool_matrix),
        }
    }

}

/// Match the game event.
fn handle_event(event: &mut GameEvent,
                gl: &mut Gl,
                uic: &mut UIContext,
                bg_color: &mut Color,
                show_button: &mut bool,
                toggle_label: &mut String,
                title_padding: &mut f64,
                v_slider_height: &mut f64,
                frame_width: &mut f64,
                bool_matrix: &mut Vec<Vec<bool>>) {
    uic.event(event);
    match *event {
        Render(ref mut args) => {
            draw_background(args, gl, bg_color);
            draw_ui(args,
                    gl,
                    uic,
                    bg_color,
                    show_button,
                    toggle_label,
                    title_padding,
                    v_slider_height,
                    frame_width,
                    bool_matrix);
        },
        _ => (),
    }
}

/// Draw the window background.
fn draw_background(args: &RenderArgs,
                   gl: &mut Gl,
                   bg_color: &mut Color) {
    // Set up a context to draw into.
    let context = &Context::abs(args.width as f64, args.height as f64);
    // Return the individual  elements of the background color.
    let (r, g, b, a) = bg_color.as_tuple();
    // Draw the background.
    context.rgba(r, g, b, a).draw(gl);
}

/// Draw the User Interface.
fn draw_ui(args: &RenderArgs,
           gl: &mut Gl,
           uic: &mut UIContext,
           bg_color: &mut Color,
           show_button: &mut bool,
           toggle_label: &mut String,
           title_padding: &mut f64,
           v_slider_height: &mut f64,
           frame_width: &mut f64,
           bool_matrix: &mut Vec<Vec<bool>>) {

    // Label example.
    label::draw(args, // RenderArgs.
                gl, // Open GL instance.
                uic, // UIContext.
                Point::new(*title_padding, 30f64, 0f64), // Screen position.
                48u32, // Font size.
                bg_color.plain_contrast(),
                "Widgets Demonstration");

    if *show_button {
        // Button widget example.
        button::draw(args, // RenderArgs.
                     gl, // Open GL instance.
                     uic, // UIContext.
                     0u64, // UI ID.
                     Point::new(50f64, 115f64, 0f64), // Screen position.
                     90f64, // Width.
                     60f64, // Height.
                     Frame(*frame_width, Color::black()), // Widget Frame.
                     Color::new(0.4f32, 0.75f32, 0.6f32, 1f32), // Button Color.
                     Label("PRESS", 24u32, Color::black()), // Label for button.
                     || { // Button "callback" event.
            *bg_color = Color::random();
        });
    }

    // Horizontal slider example.
    else {

        // Create the label for the slider.
        let pad = *title_padding as i16;
        let pad_string = pad.to_string();
        let label = "Padding: ".to_string().append(pad_string.as_slice());

        // Draw the slider.
        slider::draw(args, // RenderArgs.
                     gl, // OpenGL Instance.
                     uic, // UIContext.
                     1u64, // UIID
                     Point::new(50.0f64, 115.0, 0.0), // Screen position.
                     200f64, // Width.
                     50f64, // Height.
                     Frame(*frame_width, Color::black()), // Widget Frame.
                     Color::new(0.5, 0.3, 0.6, 1.0), // Rectangle color.
                     //NoLabel,
                     Label(label.as_slice(), 24u32, Color::white()),
                     pad as i16, // Slider value.
                     10i16, // Min value.
                     250i16, // Max value.
                     |new_pad| {
            *title_padding = new_pad as f64;
        });

    }

    // Clone the label toggle to be drawn.
    let label = toggle_label.clone();

    // Toggle widget example.
    toggle::draw(args, // RenderArgs.
                 gl, // Open GL instance.
                 uic, // UIContext.
                 2u64, // UI ID.
                 Point::new(50f64, 200f64, 0f64), // Screen position.
                 75f64, // Width.
                 75f64, // Height.
                 Frame(*frame_width, Color::black()), // Widget Frame.
                 Color::new(0.6f32, 0.25f32, 0.75f32, 1f32), // Button Color.
                 Label(label.as_slice(), 24u32, Color::white()),
                 *show_button, // bool.
                 |value| {
        *show_button = value;
        match value {
            true => {
                *toggle_label = "ON".to_string();
            },
            false => {
                *toggle_label = "OFF".to_string();
            },
        }
    });

    // Let's draw a slider for each color element.
    // 0 => red, 1 => green, 2 => blue.
    for i in range(0u, 3) {

        // We'll color the slider similarly to the color element which it will control.
        let color = match i {
            0u => Color::new(0.75f32, 0.3f32, 0.3f32, 1f32),
            1u => Color::new(0.3f32, 0.75f32, 0.3f32, 1f32),
            _  => Color::new(0.3f32, 0.3f32, 0.75f32, 1f32),
        };

        // Grab the value of the color element.
        let value = match i {
            0u => bg_color.r(),
            1u => bg_color.g(),
            _  => bg_color.b(),
        };

        // Create the label to be drawn with the slider.
        let mut label = value.to_string();
        if label.len() > 4u { label.truncate(4u); }

        // Vertical slider widget example.
        slider::draw(args, // RenderArgs.
                     gl, // Open GL instance
                     uic, // UIContext.
                     3u64 + i as u64, // UI ID.
                     Point::new(50f64 + i as f64 * 60f64, 300f64, 0f64), // Position.
                     35f64, // Width.
                     *v_slider_height, // Height.
                     Frame(*frame_width, Color::black()), // Widget Frame.
                     color, // Slider color.
                     //NoLabel,
                     Label(label.as_slice(), 24u32, Color::white()),
                     value, // Slider value.
                     0f32, // Minimum value.
                     1f32, // Maximum value.
                     |color| {
            match i {
                0u => { bg_color.set_r(color); },
                1u => { bg_color.set_g(color); },
                _ => { bg_color.set_b(color); },
            }
        });

    }

    // Number Dialer example.
    number_dialer::draw(args, // RenderArgs.
                        gl, // OpenGL instance.
                        uic, // UIContext.
                        6u64, // UIID.
                        Point::new(350.0, 115.0, 0.0), // Position.
                        24u32, // Number Dialer font size.
                        Frame(*frame_width, Color::black()), // Widget Frame
                        bg_color.invert(), // Number Dialer Color.
                        Label("Height (pixels)", 24u32, bg_color.invert().plain_contrast()),
                        *v_slider_height, // Initial value.
                        25f64, // Minimum value.
                        250f64, // Maximum value.
                        1u8, // Precision (number of digits to show after decimal point).
                        |new_height| { // Callback closure.
        *v_slider_height = new_height;
    });

    // Number Dialer example.
    number_dialer::draw(args, // RenderArgs.
                        gl, // OpenGL instance.
                        uic, // UIContext.
                        7u64, // UIID.
                        Point::new(350.0, 195.0, 0.0), // Position.
                        24u32, // Number Dialer font size.
                        Frame(4.0, bg_color.plain_contrast()), // Widget Frame
                        bg_color.invert().plain_contrast(), // Number Dialer Color.
                        Label("Frame (pixels)", 24u32, bg_color.plain_contrast()),
                        *frame_width, // Initial value.
                        0f64, // Minimum value.
                        15f64, // Maximum value.
                        2u8, // Precision (number of digits to show after decimal point).
                        |new_width| { // Callback closure.
        *frame_width = new_width;
    });

    // A demonstration using widget_matrix to easily draw
    // a matrix of any kind of widget.
    let (cols, rows) = (8u, 8u);
    widget_matrix::draw(cols, // cols.
                        rows, // rows.
                        Point::new(300.0, 270.0, 0.0), // matrix position.
                        260.0, // width.
                        260.0, // height.
                        |num, col, row, pos, width, height| {
        // Now draw the widgets with the given callback.
        let val = (*bool_matrix)[col][row];
        toggle::draw(args, gl, uic, 8u64 + num as u64, pos, width, height,
                     Frame(*frame_width, Color::black()),
                     Color::new(0.5 + (col as f32 / cols as f32) / 2.0,
                                0.75,
                                1.0 - (row as f32 / rows as f32) / 2.0,
                                1.0),
                     NoLabel,
                     val,
                     |new_val| {
            *bool_matrix.get_mut(col).get_mut(row) = new_val;
        });
    });

}

<commit_msg>Tweaked default values for nicer demo<commit_after>
#![feature(phase)]

#[phase(plugin, link)]
extern crate conrod;
extern crate graphics;
extern crate piston;
extern crate sdl2_game_window;
extern crate opengl_graphics;

use sdl2_game_window::GameWindowSDL2;
use opengl_graphics::Gl;
use piston::{
    Game,
    GameEvent,
    GameWindowSettings,
    GameIterator,
    GameIteratorSettings,
    RenderArgs,
    Render,
};
use conrod::{
    button,
    label,
    number_dialer,
    slider,
    toggle,
    widget_matrix,
    Color,
    Point,
    Frame,
    UIContext,
};
use conrod::label::{
    Label,
    NoLabel,
};
use graphics::{
    Context,
    AddColor,
    Draw,
};

fn main() {

    // Create a SDL2 window.
    let mut window = GameWindowSDL2::new(
        GameWindowSettings {
            title: "Hello Conrod".to_string(),
            size: [600, 600],
            fullscreen: false,
            exit_on_esc: true
        }
    );

    // Some settings for how the game should be run.
    let game_iter_settings = GameIteratorSettings {
        updates_per_second: 180,
        max_frames_per_second: 60
    };

    // Create GameIterator to begin the event iteration loop.
    let mut game_iter = GameIterator::new(&mut window, &game_iter_settings);
    // Create OpenGL instance.
    let mut gl = Gl::new();
    // Create the UIContext and specify the name of a font that's in our "assets" directory.
    let mut uic = UIContext::new("Dense-Regular.otf");

    // TODO: Put the following vars all in an 'app' struct or something and pass
    // as a mut reference to struct instead.

    // Background color (for demonstration of button and sliders).
    let mut bg_color = Color::new(0.2, 0.35, 0.45, 1.0);
    // Should the button be shown (for demonstration of button).
    let mut show_button = false;
    // The label that will be drawn to the Toggle.
    let mut toggle_label = "OFF".to_string();
    // The number of pixels between the left side of the window and the title.
    let mut title_padding = 50f64;
    // The height of the vertical sliders (we will play with this using a number_dialer).
    let mut v_slider_height = 185f64;
    // The widget frame width (we'll use this to demo Framing and number_dialer).
    let mut frame_width = 1f64;
    // Bool matrix for widget_matrix demonstration.
    let mut bool_matrix = vec![
                            vec![true, true, true, true, true, true, true, true],
                            vec![true, false, false, false, false, true, true, true],
                            vec![true, false, true, true, false, true, false, true],
                            vec![true, false, false, false, false, true, true, true],
                            vec![true, false, true, true, true, true, false, true],
                            vec![true, false, true, true, true, true, false, true],
                            vec![true, false, true, true, true, true, false, true],
                            vec![true, true, true, true, true, true, true, true],
                            ];

    // Main program loop begins.
    loop {
        match game_iter.next() {
            None => break,
            Some(mut e) => handle_event(&mut e,
                                        &mut gl,
                                        &mut uic,
                                        &mut bg_color,
                                        &mut show_button,
                                        &mut toggle_label,
                                        &mut title_padding,
                                        &mut v_slider_height,
                                        &mut frame_width,
                                        &mut bool_matrix),
        }
    }

}

/// Match the game event.
fn handle_event(event: &mut GameEvent,
                gl: &mut Gl,
                uic: &mut UIContext,
                bg_color: &mut Color,
                show_button: &mut bool,
                toggle_label: &mut String,
                title_padding: &mut f64,
                v_slider_height: &mut f64,
                frame_width: &mut f64,
                bool_matrix: &mut Vec<Vec<bool>>) {
    uic.event(event);
    match *event {
        Render(ref mut args) => {
            draw_background(args, gl, bg_color);
            draw_ui(args,
                    gl,
                    uic,
                    bg_color,
                    show_button,
                    toggle_label,
                    title_padding,
                    v_slider_height,
                    frame_width,
                    bool_matrix);
        },
        _ => (),
    }
}

/// Draw the window background.
fn draw_background(args: &RenderArgs,
                   gl: &mut Gl,
                   bg_color: &mut Color) {
    // Set up a context to draw into.
    let context = &Context::abs(args.width as f64, args.height as f64);
    // Return the individual  elements of the background color.
    let (r, g, b, a) = bg_color.as_tuple();
    // Draw the background.
    context.rgba(r, g, b, a).draw(gl);
}

/// Draw the User Interface.
fn draw_ui(args: &RenderArgs,
           gl: &mut Gl,
           uic: &mut UIContext,
           bg_color: &mut Color,
           show_button: &mut bool,
           toggle_label: &mut String,
           title_padding: &mut f64,
           v_slider_height: &mut f64,
           frame_width: &mut f64,
           bool_matrix: &mut Vec<Vec<bool>>) {

    // Label example.
    label::draw(args, // RenderArgs.
                gl, // Open GL instance.
                uic, // UIContext.
                Point::new(*title_padding, 30f64, 0f64), // Screen position.
                48u32, // Font size.
                bg_color.plain_contrast(),
                "Widgets Demonstration");

    if *show_button {
        // Button widget example.
        button::draw(args, // RenderArgs.
                     gl, // Open GL instance.
                     uic, // UIContext.
                     0u64, // UI ID.
                     Point::new(50f64, 115f64, 0f64), // Screen position.
                     90f64, // Width.
                     60f64, // Height.
                     Frame(*frame_width, Color::black()), // Widget Frame.
                     Color::new(0.4f32, 0.75f32, 0.6f32, 1f32), // Button Color.
                     Label("PRESS", 24u32, Color::black()), // Label for button.
                     || { // Button "callback" event.
            *bg_color = Color::random();
        });
    }

    // Horizontal slider example.
    else {

        // Create the label for the slider.
        let pad = *title_padding as i16;
        let pad_string = pad.to_string();
        let label = "Padding: ".to_string().append(pad_string.as_slice());

        // Draw the slider.
        slider::draw(args, // RenderArgs.
                     gl, // OpenGL Instance.
                     uic, // UIContext.
                     1u64, // UIID
                     Point::new(50.0f64, 115.0, 0.0), // Screen position.
                     200f64, // Width.
                     50f64, // Height.
                     Frame(*frame_width, Color::black()), // Widget Frame.
                     Color::new(0.5, 0.3, 0.6, 1.0), // Rectangle color.
                     //NoLabel,
                     Label(label.as_slice(), 24u32, Color::white()),
                     pad as i16, // Slider value.
                     10i16, // Min value.
                     250i16, // Max value.
                     |new_pad| {
            *title_padding = new_pad as f64;
        });

    }

    // Clone the label toggle to be drawn.
    let label = toggle_label.clone();

    // Toggle widget example.
    toggle::draw(args, // RenderArgs.
                 gl, // Open GL instance.
                 uic, // UIContext.
                 2u64, // UI ID.
                 Point::new(50f64, 200f64, 0f64), // Screen position.
                 75f64, // Width.
                 75f64, // Height.
                 Frame(*frame_width, Color::black()), // Widget Frame.
                 Color::new(0.6f32, 0.25f32, 0.75f32, 1f32), // Button Color.
                 Label(label.as_slice(), 24u32, Color::white()),
                 *show_button, // bool.
                 |value| {
        *show_button = value;
        match value {
            true => {
                *toggle_label = "ON".to_string();
            },
            false => {
                *toggle_label = "OFF".to_string();
            },
        }
    });

    // Let's draw a slider for each color element.
    // 0 => red, 1 => green, 2 => blue.
    for i in range(0u, 3) {

        // We'll color the slider similarly to the color element which it will control.
        let color = match i {
            0u => Color::new(0.75f32, 0.3f32, 0.3f32, 1f32),
            1u => Color::new(0.3f32, 0.75f32, 0.3f32, 1f32),
            _  => Color::new(0.3f32, 0.3f32, 0.75f32, 1f32),
        };

        // Grab the value of the color element.
        let value = match i {
            0u => bg_color.r(),
            1u => bg_color.g(),
            _  => bg_color.b(),
        };

        // Create the label to be drawn with the slider.
        let mut label = value.to_string();
        if label.len() > 4u { label.truncate(4u); }

        // Vertical slider widget example.
        slider::draw(args, // RenderArgs.
                     gl, // Open GL instance
                     uic, // UIContext.
                     3u64 + i as u64, // UI ID.
                     Point::new(50f64 + i as f64 * 60f64, 300f64, 0f64), // Position.
                     35f64, // Width.
                     *v_slider_height, // Height.
                     Frame(*frame_width, Color::black()), // Widget Frame.
                     color, // Slider color.
                     //NoLabel,
                     Label(label.as_slice(), 24u32, Color::white()),
                     value, // Slider value.
                     0f32, // Minimum value.
                     1f32, // Maximum value.
                     |color| {
            match i {
                0u => { bg_color.set_r(color); },
                1u => { bg_color.set_g(color); },
                _ => { bg_color.set_b(color); },
            }
        });

    }

    // Number Dialer example.
    number_dialer::draw(args, // RenderArgs.
                        gl, // OpenGL instance.
                        uic, // UIContext.
                        6u64, // UIID.
                        Point::new(350.0, 115.0, 0.0), // Position.
                        24u32, // Number Dialer font size.
                        Frame(*frame_width, Color::black()), // Widget Frame
                        bg_color.invert(), // Number Dialer Color.
                        Label("Height (pixels)", 24u32, bg_color.invert().plain_contrast()),
                        *v_slider_height, // Initial value.
                        25f64, // Minimum value.
                        250f64, // Maximum value.
                        1u8, // Precision (number of digits to show after decimal point).
                        |new_height| { // Callback closure.
        *v_slider_height = new_height;
    });

    // Number Dialer example.
    number_dialer::draw(args, // RenderArgs.
                        gl, // OpenGL instance.
                        uic, // UIContext.
                        7u64, // UIID.
                        Point::new(350.0, 195.0, 0.0), // Position.
                        24u32, // Number Dialer font size.
                        Frame(4.0, bg_color.plain_contrast()), // Widget Frame
                        bg_color.invert().plain_contrast(), // Number Dialer Color.
                        Label("Frame (pixels)", 24u32, bg_color.plain_contrast()),
                        *frame_width, // Initial value.
                        0f64, // Minimum value.
                        15f64, // Maximum value.
                        2u8, // Precision (number of digits to show after decimal point).
                        |new_width| { // Callback closure.
        *frame_width = new_width;
    });

    // A demonstration using widget_matrix to easily draw
    // a matrix of any kind of widget.
    let (cols, rows) = (8u, 8u);
    widget_matrix::draw(cols, // cols.
                        rows, // rows.
                        Point::new(300.0, 270.0, 0.0), // matrix position.
                        260.0, // width.
                        260.0, // height.
                        |num, col, row, pos, width, height| {
        // Now draw the widgets with the given callback.
        let val = (*bool_matrix)[col][row];
        toggle::draw(args, gl, uic, 8u64 + num as u64, pos, width, height,
                     Frame(*frame_width, Color::black()),
                     Color::new(0.5 + (col as f32 / cols as f32) / 2.0,
                                0.75,
                                1.0 - (row as f32 / rows as f32) / 2.0,
                                1.0),
                     NoLabel,
                     val,
                     |new_val| {
            *bool_matrix.get_mut(col).get_mut(row) = new_val;
        });
    });

}

<|endoftext|>


<commit_before>use rand::{SeedableRng, Rng, rngs::SmallRng};

// Having more than 1 test does seem to make a difference
// (i.e., this calls ptr::swap which having just one test does not).
#[test]
fn simple1() {
    assert_eq!(4, 4);
}

#[test]
fn simple2() {
    assert_ne!(42, 24);
}

// A test that won't work on miri (tests disabling tests)
#[cfg(not(miri))]
#[test]
fn does_not_work_on_miri() {
    let x = 0u8;
    assert!(&x as *const _ as usize % 4 < 4);
}

// We also use this to test some external crates, that we cannot depend on in the compiletest suite.

#[test]
fn entropy_rng() {
    // Try seeding with "real" entropy.
    let mut rng = SmallRng::from_entropy();
    let _val = rng.gen::<i32>();
    let _val = rng.gen::<isize>();
    let _val = rng.gen::<i128>();

    // Also try per-thread RNG.
    let mut rng = rand::thread_rng();
    let _val = rng.gen::<i32>();
    let _val = rng.gen::<isize>();
    let _val = rng.gen::<i128>();
}

#[test]
fn num_cpus() {
    assert_eq!(num_cpus::get(), 1);
}
<commit_msg>Add #[should_panic] test<commit_after>use rand::{SeedableRng, Rng, rngs::SmallRng};

// Having more than 1 test does seem to make a difference
// (i.e., this calls ptr::swap which having just one test does not).
#[test]
fn simple1() {
    assert_eq!(4, 4);
}

#[test]
fn simple2() {
    assert_ne!(42, 24);
}

// A test that won't work on miri (tests disabling tests)
#[cfg(not(miri))]
#[test]
fn does_not_work_on_miri() {
    let x = 0u8;
    assert!(&x as *const _ as usize % 4 < 4);
}

// We also use this to test some external crates, that we cannot depend on in the compiletest suite.

#[test]
fn entropy_rng() {
    // Try seeding with "real" entropy.
    let mut rng = SmallRng::from_entropy();
    let _val = rng.gen::<i32>();
    let _val = rng.gen::<isize>();
    let _val = rng.gen::<i128>();

    // Also try per-thread RNG.
    let mut rng = rand::thread_rng();
    let _val = rng.gen::<i32>();
    let _val = rng.gen::<isize>();
    let _val = rng.gen::<i128>();
}

#[test]
fn num_cpus() {
    assert_eq!(num_cpus::get(), 1);
}

#[test]
#[should_panic]
fn do_panic() { // In large, friendly letters :)
    panic!("Explicit panic from test!");
}
<|endoftext|>


<commit_before>#![feature(iter_arith)]
trait Ingredient {
    fn capacity() -> i64;
    fn durability() -> i64;
    fn flavor() -> i64;
    fn texture() -> i64;
    fn calories() -> i64;
}

struct Sprinkles;
struct PeanutButter;
struct Frosting;
struct Sugar;

// just gonna hard code this stuff
impl Ingredient for Sprinkles {
    fn capacity() -> i64 { 5 }
    fn durability() -> i64 { -1 }
    fn flavor() -> i64 { 0 }
    fn texture() -> i64 { 0 }
    fn calories() -> i64 { 5 }
}
impl Ingredient for PeanutButter {
    fn capacity() -> i64 { -1 }
    fn durability() -> i64 { 3 }
    fn flavor() -> i64 { 0 }
    fn texture() -> i64 { 0 }
    fn calories() -> i64 { 1 }
}
impl Ingredient for Frosting {
    fn capacity() -> i64 { 0 }
    fn durability() -> i64 { -1 }
    fn flavor() -> i64 { 4 }
    fn texture() -> i64 { 0 }
    fn calories() -> i64 { 6 }
}
impl Ingredient for Sugar {
    fn capacity() -> i64 { -1 }
    fn durability() -> i64 { 0 }
    fn flavor() -> i64 { 0 }
    fn texture() -> i64 { 2 }
    fn calories() -> i64 { 8 }
}

fn capacity(sprinkles: i64, peanut_butter: i64, frosting: i64, sugar: i64) -> i64 {
    Sprinkles::capacity() * sprinkles +
        PeanutButter::capacity() * peanut_butter +
        Frosting::capacity() * frosting +
        Sugar::capacity() * sugar
}
fn durability(sprinkles: i64, peanut_butter: i64, frosting: i64, sugar: i64) -> i64 {
    Sprinkles::durability() * sprinkles +
        PeanutButter::durability() * peanut_butter +
        Frosting::durability() * frosting +
        Sugar::durability() * sugar
}
fn flavor(sprinkles: i64, peanut_butter: i64, frosting: i64, sugar: i64) -> i64 {
    Sprinkles::flavor() * sprinkles +
        PeanutButter::flavor() * peanut_butter +
        Frosting::flavor() * frosting +
        Sugar::flavor() * sugar
}
fn texture(sprinkles: i64, peanut_butter: i64, frosting: i64, sugar: i64) -> i64 {
    Sprinkles::texture() * sprinkles +
        PeanutButter::texture() * peanut_butter +
        Frosting::texture() * frosting +
        Sugar::texture() * sugar
}
fn calories(sprinkles: i64, peanut_butter: i64, frosting: i64, sugar: i64) -> i64 {
    Sprinkles::calories() * sprinkles +
        PeanutButter::calories() * peanut_butter +
        Frosting::calories() * frosting +
        Sugar::calories() * sugar
}

fn score(sprinkles: i64, peanut_butter: i64, frosting: i64, sugar: i64) -> i64 {
    let amounts = vec![
        capacity(sprinkles, peanut_butter, frosting, sugar),
        durability(sprinkles, peanut_butter, frosting, sugar),
        flavor(sprinkles, peanut_butter, frosting, sugar),
        texture(sprinkles, peanut_butter, frosting, sugar),
    ];
    if amounts.iter().any(|v| *v < 0) {
        0
    } else {
        amounts.iter().product()
    }
}

fn main() {
    let mut bs = None;
    let mut best = (25, 25, 25, 25);
    for sprinkles in (0..101) {
        for pb in (0..101) {
            for frosting in (0..101) {
                for sugar in (0..101) {
                    if sprinkles + pb + frosting + sugar == 100 {
                        let this_score = score(sprinkles, pb, frosting, sugar);
                        if bs.is_none() || bs.unwrap() < this_score {
                            bs = Some(this_score);
                            best = (sprinkles, pb, frosting, sugar);
                        }
                    }
                }
            }
        }
    }
    println!("({}, {}, {}, {}): {}",
        best.0, best.1, best.2, best.3, bs.unwrap());
}
<commit_msg>day 15, part 2<commit_after>#![feature(iter_arith)]
trait Ingredient {
    fn capacity() -> i64;
    fn durability() -> i64;
    fn flavor() -> i64;
    fn texture() -> i64;
    fn calories() -> i64;
}

struct Sprinkles;
struct PeanutButter;
struct Frosting;
struct Sugar;

// just gonna hard code this stuff
impl Ingredient for Sprinkles {
    fn capacity() -> i64 { 5 }
    fn durability() -> i64 { -1 }
    fn flavor() -> i64 { 0 }
    fn texture() -> i64 { 0 }
    fn calories() -> i64 { 5 }
}
impl Ingredient for PeanutButter {
    fn capacity() -> i64 { -1 }
    fn durability() -> i64 { 3 }
    fn flavor() -> i64 { 0 }
    fn texture() -> i64 { 0 }
    fn calories() -> i64 { 1 }
}
impl Ingredient for Frosting {
    fn capacity() -> i64 { 0 }
    fn durability() -> i64 { -1 }
    fn flavor() -> i64 { 4 }
    fn texture() -> i64 { 0 }
    fn calories() -> i64 { 6 }
}
impl Ingredient for Sugar {
    fn capacity() -> i64 { -1 }
    fn durability() -> i64 { 0 }
    fn flavor() -> i64 { 0 }
    fn texture() -> i64 { 2 }
    fn calories() -> i64 { 8 }
}

fn capacity(sprinkles: i64, peanut_butter: i64, frosting: i64, sugar: i64) -> i64 {
    Sprinkles::capacity() * sprinkles +
        PeanutButter::capacity() * peanut_butter +
        Frosting::capacity() * frosting +
        Sugar::capacity() * sugar
}
fn durability(sprinkles: i64, peanut_butter: i64, frosting: i64, sugar: i64) -> i64 {
    Sprinkles::durability() * sprinkles +
        PeanutButter::durability() * peanut_butter +
        Frosting::durability() * frosting +
        Sugar::durability() * sugar
}
fn flavor(sprinkles: i64, peanut_butter: i64, frosting: i64, sugar: i64) -> i64 {
    Sprinkles::flavor() * sprinkles +
        PeanutButter::flavor() * peanut_butter +
        Frosting::flavor() * frosting +
        Sugar::flavor() * sugar
}
fn texture(sprinkles: i64, peanut_butter: i64, frosting: i64, sugar: i64) -> i64 {
    Sprinkles::texture() * sprinkles +
        PeanutButter::texture() * peanut_butter +
        Frosting::texture() * frosting +
        Sugar::texture() * sugar
}
fn calories(sprinkles: i64, peanut_butter: i64, frosting: i64, sugar: i64) -> i64 {
    Sprinkles::calories() * sprinkles +
        PeanutButter::calories() * peanut_butter +
        Frosting::calories() * frosting +
        Sugar::calories() * sugar
}

fn score(sprinkles: i64, peanut_butter: i64, frosting: i64, sugar: i64) -> i64 {
    let amounts = vec![
        capacity(sprinkles, peanut_butter, frosting, sugar),
        durability(sprinkles, peanut_butter, frosting, sugar),
        flavor(sprinkles, peanut_butter, frosting, sugar),
        texture(sprinkles, peanut_butter, frosting, sugar),
    ];
    if amounts.iter().any(|v| *v < 0) {
        0
    } else {
        amounts.iter().product()
    }
}

fn main() {
    let mut bs = None;
    let mut best = (25, 25, 25, 25);
    for sprinkles in (0..101) {
        for pb in (0..101) {
            for frosting in (0..101) {
                for sugar in (0..101) {
                    if sprinkles + pb + frosting + sugar != 100 {
                        continue;
                    }
                    if calories(sprinkles, pb, frosting, sugar) != 500 {
                        continue;
                    }
                    let this_score = score(sprinkles, pb, frosting, sugar);
                    if bs.is_none() || bs.unwrap() < this_score {
                        bs = Some(this_score);
                        best = (sprinkles, pb, frosting, sugar);
                    }
                }
            }
        }
    }
    println!("({}, {}, {}, {}): {}",
        best.0, best.1, best.2, best.3, bs.unwrap());
}
<|endoftext|>


<commit_before>//! These structs are a subset of the ones found in `rustc_errors::json`.
//! They are only used for deserialization of JSON output provided by libtest.

use crate::errors::{Error, ErrorKind};
use crate::runtest::ProcRes;
use serde::Deserialize;
use std::path::{Path, PathBuf};
use std::str::FromStr;

#[derive(Deserialize)]
struct Diagnostic {
    message: String,
    code: Option<DiagnosticCode>,
    level: String,
    spans: Vec<DiagnosticSpan>,
    children: Vec<Diagnostic>,
    rendered: Option<String>,
}

#[derive(Deserialize)]
struct ArtifactNotification {
    #[allow(dead_code)]
    artifact: PathBuf,
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpan {
    file_name: String,
    line_start: usize,
    line_end: usize,
    column_start: usize,
    column_end: usize,
    is_primary: bool,
    label: Option<String>,
    suggested_replacement: Option<String>,
    expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
}

#[derive(Deserialize)]
struct FutureIncompatReport {
    future_incompat_report: Vec<FutureBreakageItem>
}

#[derive(Deserialize)]
struct FutureBreakageItem {
    future_breakage_date: Option<String>,
    diagnostic: Diagnostic
}

impl DiagnosticSpan {
    /// Returns the deepest source span in the macro call stack with a given file name.
    /// This is either the supplied span, or the span for some macro callsite that expanded to it.
    fn first_callsite_in_file(&self, file_name: &str) -> &DiagnosticSpan {
        if self.file_name == file_name {
            self
        } else {
            self.expansion
                .as_ref()
                .map(|origin| origin.span.first_callsite_in_file(file_name))
                .unwrap_or(self)
        }
    }
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpanMacroExpansion {
    /// span where macro was applied to generate this code
    span: DiagnosticSpan,

    /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
    macro_decl_name: String,
}

#[derive(Deserialize, Clone)]
struct DiagnosticCode {
    /// The code itself.
    code: String,
    /// An explanation for the code.
    explanation: Option<String>,
}

pub fn extract_rendered(output: &str) -> String {
    output
        .lines()
        .filter_map(|line| {
            if line.starts_with('{') {
                if let Ok(diagnostic) = serde_json::from_str::<Diagnostic>(line) {
                    diagnostic.rendered
                } else if serde_json::from_str::<ArtifactNotification>(line).is_ok() {
                    // Ignore the notification.
                    None
                } else {
                    print!(
                        "failed to decode compiler output as json: line: {}\noutput: {}",
                        line, output
                    );
                    panic!()
                }
            } else {
                // preserve non-JSON lines, such as ICEs
                Some(format!("{}\n", line))
            }
        })
        .collect()
}

pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    let lines = output.lines();
    let last_line = lines.next_back();
    lines.flat_map(|line| parse_line(file_name, line, output, proc_res, false)).chain(
        last_line.into_iter().flat_map(|line| parse_line(file_name, line, output, proc_res, true))
    ).collect()
}

fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes, last_line: bool) -> Vec<Error> {
    // The compiler sometimes intermingles non-JSON stuff into the
    // output.  This hack just skips over such lines. Yuck.
    if line.starts_with('{') {
        match serde_json::from_str::<Diagnostic>(line) {
            Ok(diagnostic) => {
                let mut expected_errors = vec![];
                push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name);
                expected_errors
            }
            Err(error) => {
                proc_res.fatal(Some(&format!(
                    "failed to decode compiler output as json: \
                     `{}`\nline: {}\noutput: {}",
                    error, line, output
                )));
            }
        }
    } else {
        vec![]
    }
}

fn push_expected_errors(
    expected_errors: &mut Vec<Error>,
    diagnostic: &Diagnostic,
    default_spans: &[&DiagnosticSpan],
    file_name: &str,
) {
    // In case of macro expansions, we need to get the span of the callsite
    let spans_info_in_this_file: Vec<_> = diagnostic
        .spans
        .iter()
        .map(|span| (span.is_primary, span.first_callsite_in_file(file_name)))
        .filter(|(_, span)| Path::new(&span.file_name) == Path::new(&file_name))
        .collect();

    let spans_in_this_file: Vec<_> = spans_info_in_this_file.iter().map(|(_, span)| span).collect();

    let primary_spans: Vec<_> = spans_info_in_this_file
        .iter()
        .filter(|(is_primary, _)| *is_primary)
        .map(|(_, span)| span)
        .take(1) // sometimes we have more than one showing up in the json; pick first
        .cloned()
        .collect();
    let primary_spans = if primary_spans.is_empty() {
        // subdiagnostics often don't have a span of their own;
        // inherit the span from the parent in that case
        default_spans
    } else {
        &primary_spans
    };

    // We break the output into multiple lines, and then append the
    // [E123] to every line in the output. This may be overkill.  The
    // intention was to match existing tests that do things like "//|
    // found `i32` [E123]" and expect to match that somewhere, and yet
    // also ensure that `//~ ERROR E123` *always* works. The
    // assumption is that these multi-line error messages are on their
    // way out anyhow.
    let with_code = |span: &DiagnosticSpan, text: &str| {
        match diagnostic.code {
            Some(ref code) =>
            // FIXME(#33000) -- it'd be better to use a dedicated
            // UI harness than to include the line/col number like
            // this, but some current tests rely on it.
            //
            // Note: Do NOT include the filename. These can easily
            // cause false matches where the expected message
            // appears in the filename, and hence the message
            // changes but the test still passes.
            {
                format!(
                    "{}:{}: {}:{}: {} [{}]",
                    span.line_start,
                    span.column_start,
                    span.line_end,
                    span.column_end,
                    text,
                    code.code.clone()
                )
            }
            None =>
            // FIXME(#33000) -- it'd be better to use a dedicated UI harness
            {
                format!(
                    "{}:{}: {}:{}: {}",
                    span.line_start, span.column_start, span.line_end, span.column_end, text
                )
            }
        }
    };

    // Convert multi-line messages into multiple expected
    // errors. We expect to replace these with something
    // more structured shortly anyhow.
    let mut message_lines = diagnostic.message.lines();
    if let Some(first_line) = message_lines.next() {
        for span in primary_spans {
            let msg = with_code(span, first_line);
            let kind = ErrorKind::from_str(&diagnostic.level).ok();
            expected_errors.push(Error { line_num: span.line_start, kind, msg });
        }
    }
    for next_line in message_lines {
        for span in primary_spans {
            expected_errors.push(Error {
                line_num: span.line_start,
                kind: None,
                msg: with_code(span, next_line),
            });
        }
    }

    // If the message has a suggestion, register that.
    for span in primary_spans {
        if let Some(ref suggested_replacement) = span.suggested_replacement {
            for (index, line) in suggested_replacement.lines().enumerate() {
                expected_errors.push(Error {
                    line_num: span.line_start + index,
                    kind: Some(ErrorKind::Suggestion),
                    msg: line.to_string(),
                });
            }
        }
    }

    // Add notes for the backtrace
    for span in primary_spans {
        for frame in &span.expansion {
            push_backtrace(expected_errors, frame, file_name);
        }
    }

    // Add notes for any labels that appear in the message.
    for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) {
        expected_errors.push(Error {
            line_num: span.line_start,
            kind: Some(ErrorKind::Note),
            msg: span.label.clone().unwrap(),
        });
    }

    // Flatten out the children.
    for child in &diagnostic.children {
        push_expected_errors(expected_errors, child, primary_spans, file_name);
    }
}

fn push_backtrace(
    expected_errors: &mut Vec<Error>,
    expansion: &DiagnosticSpanMacroExpansion,
    file_name: &str,
) {
    if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
        expected_errors.push(Error {
            line_num: expansion.span.line_start,
            kind: Some(ErrorKind::Note),
            msg: format!("in this expansion of {}", expansion.macro_decl_name),
        });
    }

    for previous_expansion in &expansion.span.expansion {
        push_backtrace(expected_errors, previous_expansion, file_name);
    }
}
<commit_msg>Print future breakage report<commit_after>//! These structs are a subset of the ones found in `rustc_errors::json`.
//! They are only used for deserialization of JSON output provided by libtest.

use crate::errors::{Error, ErrorKind};
use crate::runtest::ProcRes;
use serde::Deserialize;
use std::path::{Path, PathBuf};
use std::str::FromStr;

#[derive(Deserialize)]
struct Diagnostic {
    message: String,
    code: Option<DiagnosticCode>,
    level: String,
    spans: Vec<DiagnosticSpan>,
    children: Vec<Diagnostic>,
    rendered: Option<String>,
}

#[derive(Deserialize)]
struct ArtifactNotification {
    #[allow(dead_code)]
    artifact: PathBuf,
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpan {
    file_name: String,
    line_start: usize,
    line_end: usize,
    column_start: usize,
    column_end: usize,
    is_primary: bool,
    label: Option<String>,
    suggested_replacement: Option<String>,
    expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
}

#[derive(Deserialize)]
struct FutureIncompatReport {
    future_incompat_report: Vec<FutureBreakageItem>
}

#[derive(Deserialize)]
struct FutureBreakageItem {
    future_breakage_date: Option<String>,
    diagnostic: Diagnostic
}

impl DiagnosticSpan {
    /// Returns the deepest source span in the macro call stack with a given file name.
    /// This is either the supplied span, or the span for some macro callsite that expanded to it.
    fn first_callsite_in_file(&self, file_name: &str) -> &DiagnosticSpan {
        if self.file_name == file_name {
            self
        } else {
            self.expansion
                .as_ref()
                .map(|origin| origin.span.first_callsite_in_file(file_name))
                .unwrap_or(self)
        }
    }
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpanMacroExpansion {
    /// span where macro was applied to generate this code
    span: DiagnosticSpan,

    /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
    macro_decl_name: String,
}

#[derive(Deserialize, Clone)]
struct DiagnosticCode {
    /// The code itself.
    code: String,
    /// An explanation for the code.
    explanation: Option<String>,
}

pub fn extract_rendered(output: &str) -> String {
    output
        .lines()
        .filter_map(|line| {
            if line.starts_with('{') {
                if let Ok(diagnostic) = serde_json::from_str::<Diagnostic>(line) {
                    diagnostic.rendered
                } else if let Ok(report) = serde_json::from_str::<FutureIncompatReport>(line) {
                    Some(format!("Future incompatibility report: {}",
                            report.future_incompat_report.into_iter().map(|item| {
                                format!("Future breakage date: {}, diagnostic:\n{}",
                                        item.future_breakage_date.unwrap_or_else(|| "None".to_string()),
                                        item.diagnostic.rendered.unwrap_or_else(|| "Not rendered".to_string()))
                            }).collect::<String>()))
                } else if serde_json::from_str::<ArtifactNotification>(line).is_ok() {
                    // Ignore the notification.
                    None
                } else {
                    print!(
                        "failed to decode compiler output as json: line: {}\noutput: {}",
                        line, output
                    );
                    panic!()
                }
            } else {
                // preserve non-JSON lines, such as ICEs
                Some(format!("{}\n", line))
            }
        })
        .collect()
}

pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    output.lines().flat_map(|line| parse_line(file_name, line, output, proc_res)).collect()
}

fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    // The compiler sometimes intermingles non-JSON stuff into the
    // output.  This hack just skips over such lines. Yuck.
    if line.starts_with('{') {
        match serde_json::from_str::<Diagnostic>(line) {
            Ok(diagnostic) => {
                let mut expected_errors = vec![];
                push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name);
                expected_errors
            }
            Err(error) => {
                proc_res.fatal(Some(&format!(
                    "failed to decode compiler output as json: \
                     `{}`\nline: {}\noutput: {}",
                    error, line, output
                )));
            }
        }
    } else {
        vec![]
    }
}

fn push_expected_errors(
    expected_errors: &mut Vec<Error>,
    diagnostic: &Diagnostic,
    default_spans: &[&DiagnosticSpan],
    file_name: &str,
) {
    // In case of macro expansions, we need to get the span of the callsite
    let spans_info_in_this_file: Vec<_> = diagnostic
        .spans
        .iter()
        .map(|span| (span.is_primary, span.first_callsite_in_file(file_name)))
        .filter(|(_, span)| Path::new(&span.file_name) == Path::new(&file_name))
        .collect();

    let spans_in_this_file: Vec<_> = spans_info_in_this_file.iter().map(|(_, span)| span).collect();

    let primary_spans: Vec<_> = spans_info_in_this_file
        .iter()
        .filter(|(is_primary, _)| *is_primary)
        .map(|(_, span)| span)
        .take(1) // sometimes we have more than one showing up in the json; pick first
        .cloned()
        .collect();
    let primary_spans = if primary_spans.is_empty() {
        // subdiagnostics often don't have a span of their own;
        // inherit the span from the parent in that case
        default_spans
    } else {
        &primary_spans
    };

    // We break the output into multiple lines, and then append the
    // [E123] to every line in the output. This may be overkill.  The
    // intention was to match existing tests that do things like "//|
    // found `i32` [E123]" and expect to match that somewhere, and yet
    // also ensure that `//~ ERROR E123` *always* works. The
    // assumption is that these multi-line error messages are on their
    // way out anyhow.
    let with_code = |span: &DiagnosticSpan, text: &str| {
        match diagnostic.code {
            Some(ref code) =>
            // FIXME(#33000) -- it'd be better to use a dedicated
            // UI harness than to include the line/col number like
            // this, but some current tests rely on it.
            //
            // Note: Do NOT include the filename. These can easily
            // cause false matches where the expected message
            // appears in the filename, and hence the message
            // changes but the test still passes.
            {
                format!(
                    "{}:{}: {}:{}: {} [{}]",
                    span.line_start,
                    span.column_start,
                    span.line_end,
                    span.column_end,
                    text,
                    code.code.clone()
                )
            }
            None =>
            // FIXME(#33000) -- it'd be better to use a dedicated UI harness
            {
                format!(
                    "{}:{}: {}:{}: {}",
                    span.line_start, span.column_start, span.line_end, span.column_end, text
                )
            }
        }
    };

    // Convert multi-line messages into multiple expected
    // errors. We expect to replace these with something
    // more structured shortly anyhow.
    let mut message_lines = diagnostic.message.lines();
    if let Some(first_line) = message_lines.next() {
        for span in primary_spans {
            let msg = with_code(span, first_line);
            let kind = ErrorKind::from_str(&diagnostic.level).ok();
            expected_errors.push(Error { line_num: span.line_start, kind, msg });
        }
    }
    for next_line in message_lines {
        for span in primary_spans {
            expected_errors.push(Error {
                line_num: span.line_start,
                kind: None,
                msg: with_code(span, next_line),
            });
        }
    }

    // If the message has a suggestion, register that.
    for span in primary_spans {
        if let Some(ref suggested_replacement) = span.suggested_replacement {
            for (index, line) in suggested_replacement.lines().enumerate() {
                expected_errors.push(Error {
                    line_num: span.line_start + index,
                    kind: Some(ErrorKind::Suggestion),
                    msg: line.to_string(),
                });
            }
        }
    }

    // Add notes for the backtrace
    for span in primary_spans {
        for frame in &span.expansion {
            push_backtrace(expected_errors, frame, file_name);
        }
    }

    // Add notes for any labels that appear in the message.
    for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) {
        expected_errors.push(Error {
            line_num: span.line_start,
            kind: Some(ErrorKind::Note),
            msg: span.label.clone().unwrap(),
        });
    }

    // Flatten out the children.
    for child in &diagnostic.children {
        push_expected_errors(expected_errors, child, primary_spans, file_name);
    }
}

fn push_backtrace(
    expected_errors: &mut Vec<Error>,
    expansion: &DiagnosticSpanMacroExpansion,
    file_name: &str,
) {
    if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
        expected_errors.push(Error {
            line_num: expansion.span.line_start,
            kind: Some(ErrorKind::Note),
            msg: format!("in this expansion of {}", expansion.macro_decl_name),
        });
    }

    for previous_expansion in &expansion.span.expansion {
        push_backtrace(expected_errors, previous_expansion, file_name);
    }
}
<|endoftext|>


<commit_before>//! # Protobuf code generator for `protobuf` crate
//!
//! This crate is useful mostly from `build.rs` scripts to generate `.rs` files during the build.
//!
//! # How to generate code
//!
//! There are three main ways to generate `.rs` files from `.proto` files:
//! * using `protoc` command line tool and `protoc-gen-rust` plugin
//! * using this crate [`Codegen`](crate::Codegen) with pure rust parser
//! * using this crate `Codegen` with `protoc` parser
//!
//! Which one should you use depends on your needs.
//!
//! If you are using non-cargo build system (like Bazel), you might prefer
//! using `protoc-gen-rust` plugin for `protoc`.
//!
//! If you build with `cargo`, you probably want to use `Codegen` from this crate.
//!
//! # Protoc parser vs pure rust parser
//!
//! There are two protobuf parsers which can be plugged into this crate:
//! * `protoc`-based parser (`protoc` is a command like utility from Google protobuf)
//! * pure rust parser (`protobuf-parse` crate)
//!
//! `protoc`-based parser is expected to parse `.proto` files very correctly:
//! all Google's protobuf implementations rely on it.
//!
//! Where there are no known bugs in `protobuf-parse`, it is not tested very well.
//! Also `protobuf-parse` does not implement certain rarely used features of `.proto` parser,
//! mostly complex message options specified in `.proto` files.
//! I never saw anyone using them, but you have been warned.
//!
//! Note `protoc` command can be obtained from `protoc-bin-vendored` crate.
//!
//! # Version 3
//!
//! Note this is documentation for protobuf-codegen version 3 (which is currently in development).
//!
//! In version 3 this crate encapsulates both `protoc`-based codegen and pure rust codegen.
//!
//! In version 2 `protobuf-codegen` contains `protoc`-based codegen,
//! and `protobuf-codegen-pure` is pure rust codegen.

#![deny(rustdoc::broken_intra_doc_links)]

mod codegen;
mod compiler_plugin;
mod customize;
mod gen;
pub mod gen_and_write;
pub mod protoc_gen_rust;

pub use codegen::Codegen;
pub use customize::Customize;
#[doc(hidden)]
pub use gen::paths::proto_name_to_rs;
<commit_msg>Example how to invoke codegen from build.rs<commit_after>//! # Protobuf code generator for `protobuf` crate
//!
//! This crate is useful mostly from `build.rs` scripts to generate `.rs` files during the build.
//!
//! # How to generate code
//!
//! There are three main ways to generate `.rs` files from `.proto` files:
//! * using `protoc` command line tool and `protoc-gen-rust` plugin
//! * using this crate [`Codegen`](crate::Codegen) with pure rust parser
//! * using this crate `Codegen` with `protoc` parser
//!
//! Which one should you use depends on your needs.
//!
//! If you are using non-cargo build system (like Bazel), you might prefer
//! using `protoc-gen-rust` plugin for `protoc`.
//!
//! If you build with `cargo`, you probably want to use `Codegen` from this crate.
//!
//! # Protoc parser vs pure rust parser
//!
//! There are two protobuf parsers which can be plugged into this crate:
//! * `protoc`-based parser (`protoc` is a command like utility from Google protobuf)
//! * pure rust parser (`protobuf-parse` crate)
//!
//! `protoc`-based parser is expected to parse `.proto` files very correctly:
//! all Google's protobuf implementations rely on it.
//!
//! Where there are no known bugs in `protobuf-parse`, it is not tested very well.
//! Also `protobuf-parse` does not implement certain rarely used features of `.proto` parser,
//! mostly complex message options specified in `.proto` files.
//! I never saw anyone using them, but you have been warned.
//!
//! Note `protoc` command can be obtained from `protoc-bin-vendored` crate.
//!
//! # Version 3
//!
//! Note this is documentation for protobuf-codegen version 3 (which is currently in development).
//!
//! In version 3 this crate encapsulates both `protoc`-based codegen and pure rust codegen.
//!
//! In version 2 `protobuf-codegen` contains `protoc`-based codegen,
//! and `protobuf-codegen-pure` is pure rust codegen.
//!
//! # Example
//!
//! ```no_run
//! // Use this in build.rs
//! protobuf_codegen::Codegen::new()
//!     .includes(&["src/protos"])
//!     // Inputs must reside in some of include paths.
//!     .input("src/protos/apple.proto")
//!     .input("src/protos/banana.proto")
//!     .out_dir("src/protos")
//!     .run_from_script();
//! ```

#![deny(rustdoc::broken_intra_doc_links)]

mod codegen;
mod compiler_plugin;
mod customize;
mod gen;
pub mod gen_and_write;
pub mod protoc_gen_rust;

pub use codegen::Codegen;
pub use customize::Customize;
#[doc(hidden)]
pub use gen::paths::proto_name_to_rs;
<|endoftext|>