<commit_before>// MIT License
//
// Copyright (c) 2016 Rafael Medina García <rafamedgar@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/// Edit/View dialog definition

use std::cell::RefCell;
use std::os::raw::{c_int, c_double};
use std::rc::Rc;

use chrono::NaiveDate;
use glib;
use gtk;
use gtk::prelude::*;
use gtk::{
    Application,
    ApplicationWindow,
    Builder,
    Box,
    ButtonsType,
    Dialog,
    DialogFlags,
    MessageType,
    Revealer,
    Window,
    WindowPosition
};
use gtk::{
    Button,
    CellRendererText,
    Calendar,
    ComboBox,
    Entry,
    HeaderBar,
    InfoBar,
    Label,
    ListStore,
    MessageDialog,
    Popover,
    ScrolledWindow,
    Separator,
    SpinButton,
    TextView,
    ToggleButton,
    TreeIter,
    TreeView,
    TreeViewColumn
};
use regex::Regex;

use common::{State, RE_DATE, CURRENCIES, PAYMENTS};
use db;
use db::Receipt;
use gui::main_window;

/// Creates a view/edit dialog
pub fn create_window(app: &Application, state: &Rc<RefCell<State>>,
                     receipt_id: i32) -> ApplicationWindow {

    let mut title = "";
    let mut is_modal = false;
    let receipt: Receipt;

    if receipt_id >= 0 {
        title = "Edit receipt";
        receipt = db::get_receipt(state.borrow().db_path.as_str(), receipt_id).unwrap();

    } else {
        title = "New receipt";
        is_modal = true;
        receipt = Receipt::new();
    }

    let window = ApplicationWindow::new(&app);
    window.set_title(title);
    // window.set_border_width(10);
    window.set_default_size(600, 400);
    window.set_modal(is_modal);
    window.set_position(WindowPosition::Center);

    let builder = Builder::new();
    builder.add_from_string(include_str!("edit_window.ui"));

    // Header bar
    let header_bar: HeaderBar = builder.get_object("header_bar").unwrap();
    header_bar.set_title(Some(&title));
    window.set_titlebar(Some(&header_bar));

    // Container
    let main_box: Box = builder.get_object("main_box").unwrap();
    window.add(&main_box);

    // Fill stores
    let store_currency: ListStore = builder.get_object("store_currency").unwrap();
    fill_store!(combo => store_currency, CURRENCIES);

    let store_type: ListStore = builder.get_object("store_type").unwrap();
    fill_store!(combo => store_type, PAYMENTS);

    // Load data
    if receipt_id >= 0 {
        let entry_shop: Entry = builder.get_object("entry_shop").unwrap();
        entry_shop.set_text(receipt.shop.as_str());

        let entry_desc: TextView = builder.get_object("entry_desc").unwrap();
        let desc_buffer = entry_desc.get_buffer().unwrap();
        desc_buffer.set_text(receipt.description.as_str());

        let spin_cost: SpinButton = builder.get_object("spin_cost").unwrap();
        spin_cost.set_value(receipt.amount);

        let combo_type: ComboBox = builder.get_object("combo_type").unwrap();
        let payment_type = receipt.payment_type.clone();
        set_active_combo!(combo_type, PAYMENTS, payment_type);

        let combo_currency: ComboBox = builder.get_object("combo_currency").unwrap();
        let currency = receipt.currency.clone();
        set_active_combo!(combo_currency, CURRENCIES, currency);

        let entry_date: Entry = builder.get_object("entry_date").unwrap();
        entry_date.set_text(receipt.date_paid.format("%d/%m/%Y").to_string().as_str());
    }

    // Events

    // Hide the information bar
    {
        let builder = builder.clone();
        let info_bar: InfoBar = builder.get_object("info_bar").unwrap();

        let revealer: Revealer = builder.get_object("revealer").unwrap();

        info_bar.connect_response(move |_, _| {
            revealer.set_reveal_child(false);
        });
    }

    // Toogle date chooser (to)
    {
        let builder = builder.clone();
        let btn_date: Button = builder.get_object("btn_date").unwrap();

        let popover_date: Popover = builder.get_object("popover_date").unwrap();
        let entry_date: Entry = builder.get_object("entry_date").unwrap();

        btn_date.connect_clicked(move |_| {
            popover_date.set_relative_to(Some(&entry_date));
            popover_date.show_all();
        });
    }

    // Calendar chooser
    // NOTE: Months start in 0
    {
        let builder = builder.clone();
        let calendar: Calendar = builder.get_object("calendar").unwrap();

        let entry_date: Entry = builder.get_object("entry_date").unwrap();

        calendar.connect_day_selected(move |calendar| {
            let (year, month, day) = calendar.get_date();

            entry_date.set_text(format!("{}/{}/{}", day, month+1, year).as_str());
        });
    }

    // Save receipt
    {
        let builder = builder.clone();
        let btn_save: Button = builder.get_object("btn_save").unwrap();
        let state = state.clone();

        let revealer: Revealer = builder.get_object("revealer").unwrap();
        let lbl_info: Label = builder.get_object("lbl_info").unwrap();
        let lbl_info_data: Label = builder.get_object("lbl_info_data").unwrap();
        let entry_shop: Entry = builder.get_object("entry_shop").unwrap();
        let entry_desc: TextView = builder.get_object("entry_desc").unwrap();
        let spin_cost: SpinButton = builder.get_object("spin_cost").unwrap();
        let combo_type: ComboBox = builder.get_object("combo_type").unwrap();
        let combo_currency: ComboBox = builder.get_object("combo_currency").unwrap();
        let entry_date: Entry = builder.get_object("entry_date").unwrap();
        let receipt_id = receipt_id.clone();

        btn_save.connect_clicked(move |_| {
            // Check shop, date and comboboxes
            let mut error_check = Vec::new();

            let value_shop = entry_shop.get_text().unwrap();
            if value_shop.is_empty() {
                error_check.push("shop");
            }

            if combo_type.get_active() < 0 {
                error_check.push("type");
            }

            if combo_currency.get_active() < 0 {
                error_check.push("currency");
            }

            let value_date = entry_date.get_text().unwrap();
            let re_date = Regex::new(RE_DATE).unwrap();
            if value_date.is_empty() || !re_date.is_match(value_date.as_str()) {
                error_check.push("date");
            }

            if error_check.len() > 0 {
                // Show information and abort saving
                lbl_info.set_text("Check fields:");
                lbl_info_data.set_text(error_check.join(", ").as_str());

                revealer.set_reveal_child(true);

                return;
            }

            // Create receipt
            let mut receipt = receipt.clone();

            let buffer = entry_desc.get_buffer().unwrap();
            receipt.description = buffer.get_text(
                &buffer.get_start_iter(),
                &buffer.get_end_iter(),
                true
            ).unwrap();

            receipt.shop = value_shop;
            receipt.amount = spin_cost.get_value();

            let iter_type = combo_type.get_active_iter().unwrap();
            let model_type = combo_type.get_model().unwrap();
            receipt.payment_type = model_type.get_value(&iter_type, 0).get::<String>().unwrap();

            let iter_currency = combo_currency.get_active_iter().unwrap();
            let model_currency = combo_currency.get_model().unwrap();
            receipt.currency = model_currency.get_value(&iter_currency, 0).get::<String>().unwrap();

            receipt.date_paid = NaiveDate::parse_from_str(value_date.as_str(), "%d/%m/%Y").unwrap();

            // Save receipt
            let status;
            if receipt_id < 0 {
                // Creating
                status = db::insert_receipt(&state.borrow().db_path, &receipt);

            } else {
                // Updating
                status = db::update_receipt(&state.borrow().db_path, &receipt);

                // TODO check result
                lbl_info.set_text("Receipt updated");
                lbl_info_data.set_text("");

                revealer.set_reveal_child(true);
            }

            //TODO check status and show infobar if error
            glib::idle_add(main_window::refresh_table);
        });
    }

    // Window closed, remove from map if applicable
    {
        let window = window.clone();
        let state = state.clone();
        let receipt_id = receipt_id.clone();

        window.connect_delete_event(move |_, _| {
            let mut borrowed = state.borrow_mut();

            if receipt_id >= 0 && borrowed.window_map.contains_key(&receipt_id) {
                // Remove window
                borrowed.window_map.remove(&receipt_id);
            }

            Inhibit(false)
        });
    }

    window
}
<commit_msg>Show status when updating/creating receipts<commit_after>// MIT License
//
// Copyright (c) 2016 Rafael Medina García <rafamedgar@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/// Edit/View dialog definition

use std::cell::RefCell;
use std::os::raw::{c_int, c_double};
use std::rc::Rc;

use chrono::NaiveDate;
use glib;
use gtk;
use gtk::prelude::*;
use gtk::{
    Application,
    ApplicationWindow,
    Builder,
    Box,
    ButtonsType,
    Dialog,
    DialogFlags,
    MessageType,
    Revealer,
    Window,
    WindowPosition
};
use gtk::{
    Button,
    CellRendererText,
    Calendar,
    ComboBox,
    Entry,
    HeaderBar,
    InfoBar,
    Label,
    ListStore,
    MessageDialog,
    Popover,
    ScrolledWindow,
    Separator,
    SpinButton,
    TextView,
    ToggleButton,
    TreeIter,
    TreeView,
    TreeViewColumn
};
use regex::Regex;

use common::{State, RE_DATE, CURRENCIES, PAYMENTS};
use db;
use db::Receipt;
use gui::main_window;

/// Creates a view/edit dialog
pub fn create_window(app: &Application, state: &Rc<RefCell<State>>,
                     receipt_id: i32) -> ApplicationWindow {

    let mut title = "";
    let mut is_modal = false;
    let receipt: Receipt;

    if receipt_id >= 0 {
        title = "Edit receipt";
        receipt = db::get_receipt(state.borrow().db_path.as_str(), receipt_id).unwrap();

    } else {
        title = "New receipt";
        is_modal = true;
        receipt = Receipt::new();
    }

    let window = ApplicationWindow::new(&app);
    window.set_title(title);
    // window.set_border_width(10);
    window.set_default_size(600, 400);
    window.set_modal(is_modal);
    window.set_position(WindowPosition::Center);

    let builder = Builder::new();
    builder.add_from_string(include_str!("edit_window.ui"));

    // Header bar
    let header_bar: HeaderBar = builder.get_object("header_bar").unwrap();
    header_bar.set_title(Some(&title));
    window.set_titlebar(Some(&header_bar));

    // Container
    let main_box: Box = builder.get_object("main_box").unwrap();
    window.add(&main_box);

    // Fill stores
    let store_currency: ListStore = builder.get_object("store_currency").unwrap();
    fill_store!(combo => store_currency, CURRENCIES);

    let store_type: ListStore = builder.get_object("store_type").unwrap();
    fill_store!(combo => store_type, PAYMENTS);

    // Load data
    if receipt_id >= 0 {
        let entry_shop: Entry = builder.get_object("entry_shop").unwrap();
        entry_shop.set_text(receipt.shop.as_str());

        let entry_desc: TextView = builder.get_object("entry_desc").unwrap();
        let desc_buffer = entry_desc.get_buffer().unwrap();
        desc_buffer.set_text(receipt.description.as_str());

        let spin_cost: SpinButton = builder.get_object("spin_cost").unwrap();
        spin_cost.set_value(receipt.amount);

        let combo_type: ComboBox = builder.get_object("combo_type").unwrap();
        let payment_type = receipt.payment_type.clone();
        set_active_combo!(combo_type, PAYMENTS, payment_type);

        let combo_currency: ComboBox = builder.get_object("combo_currency").unwrap();
        let currency = receipt.currency.clone();
        set_active_combo!(combo_currency, CURRENCIES, currency);

        let entry_date: Entry = builder.get_object("entry_date").unwrap();
        entry_date.set_text(receipt.date_paid.format("%d/%m/%Y").to_string().as_str());
    }

    // Events

    // Hide the information bar
    {
        let builder = builder.clone();
        let info_bar: InfoBar = builder.get_object("info_bar").unwrap();

        let revealer: Revealer = builder.get_object("revealer").unwrap();

        info_bar.connect_response(move |_, _| {
            revealer.set_reveal_child(false);
        });
    }

    // Toogle date chooser (to)
    {
        let builder = builder.clone();
        let btn_date: Button = builder.get_object("btn_date").unwrap();

        let popover_date: Popover = builder.get_object("popover_date").unwrap();
        let entry_date: Entry = builder.get_object("entry_date").unwrap();

        btn_date.connect_clicked(move |_| {
            popover_date.set_relative_to(Some(&entry_date));
            popover_date.show_all();
        });
    }

    // Calendar chooser
    // NOTE: Months start in 0
    {
        let builder = builder.clone();
        let calendar: Calendar = builder.get_object("calendar").unwrap();

        let entry_date: Entry = builder.get_object("entry_date").unwrap();

        calendar.connect_day_selected(move |calendar| {
            let (year, month, day) = calendar.get_date();

            entry_date.set_text(format!("{}/{}/{}", day, month+1, year).as_str());
        });
    }

    // Save receipt
    {
        let builder = builder.clone();
        let btn_save: Button = builder.get_object("btn_save").unwrap();
        let state = state.clone();

        let revealer: Revealer = builder.get_object("revealer").unwrap();
        let lbl_info: Label = builder.get_object("lbl_info").unwrap();
        let lbl_info_data: Label = builder.get_object("lbl_info_data").unwrap();
        let entry_shop: Entry = builder.get_object("entry_shop").unwrap();
        let entry_desc: TextView = builder.get_object("entry_desc").unwrap();
        let spin_cost: SpinButton = builder.get_object("spin_cost").unwrap();
        let combo_type: ComboBox = builder.get_object("combo_type").unwrap();
        let combo_currency: ComboBox = builder.get_object("combo_currency").unwrap();
        let entry_date: Entry = builder.get_object("entry_date").unwrap();
        let receipt_id = receipt_id.clone();
        let window = window.clone();

        btn_save.connect_clicked(move |_| {
            // Check shop, date and comboboxes
            let mut error_check = Vec::new();

            let value_shop = entry_shop.get_text().unwrap();
            if value_shop.is_empty() {
                error_check.push("shop");
            }

            if combo_type.get_active() < 0 {
                error_check.push("type");
            }

            if combo_currency.get_active() < 0 {
                error_check.push("currency");
            }

            let value_date = entry_date.get_text().unwrap();
            let re_date = Regex::new(RE_DATE).unwrap();
            if value_date.is_empty() || !re_date.is_match(value_date.as_str()) {
                error_check.push("date");
            }

            if error_check.len() > 0 {
                // Show information and abort saving
                lbl_info.set_text("Check fields:");
                lbl_info_data.set_text(error_check.join(", ").as_str());

                revealer.set_reveal_child(true);

                return;
            }

            // Create receipt
            let mut receipt = receipt.clone();

            let buffer = entry_desc.get_buffer().unwrap();
            receipt.description = buffer.get_text(
                &buffer.get_start_iter(),
                &buffer.get_end_iter(),
                true
            ).unwrap();

            receipt.shop = value_shop;
            receipt.amount = spin_cost.get_value();

            let iter_type = combo_type.get_active_iter().unwrap();
            let model_type = combo_type.get_model().unwrap();
            receipt.payment_type = model_type.get_value(&iter_type, 0).get::<String>().unwrap();

            let iter_currency = combo_currency.get_active_iter().unwrap();
            let model_currency = combo_currency.get_model().unwrap();
            receipt.currency = model_currency.get_value(&iter_currency, 0).get::<String>().unwrap();

            receipt.date_paid = NaiveDate::parse_from_str(value_date.as_str(), "%d/%m/%Y").unwrap();

            // Save receipt
            let status;
            if receipt_id < 0 {
                // Creating
                status = db::insert_receipt(&state.borrow().db_path, &receipt);

            } else {
                // Updating
                status = db::update_receipt(&state.borrow().db_path, &receipt);

                lbl_info.set_text("Receipt updated");
                lbl_info_data.set_text("");
            }

            // Check status after saving
            if status.unwrap() < 1 {
                // Error, show infobar
                lbl_info.set_text("Error storing receipt");
                lbl_info_data.set_text("");

                revealer.set_reveal_child(true);

            } else {
                // Refresh table
                glib::idle_add(main_window::refresh_table);

                // Check if creating and close modal window
                if receipt_id < 0 {
                    window.close();
                }

                revealer.set_reveal_child(true);
            }
        });
    }

    // Window closed, remove from map if applicable
    {
        let window = window.clone();
        let state = state.clone();
        let receipt_id = receipt_id.clone();

        window.connect_delete_event(move |_, _| {
            let mut borrowed = state.borrow_mut();

            if receipt_id >= 0 && borrowed.window_map.contains_key(&receipt_id) {
                // Remove window
                borrowed.window_map.remove(&receipt_id);
            }

            Inhibit(false)
        });
    }

    window
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

/// A wrapper type for gzip compression level.
#[derive(Clone, Copy, Debug)]
pub struct Compression(flate2::Compression);

/// A type for defining gzip compression level for gzchunked.
impl Compression {

    pub fn new(level: u32) -> Compression {
        Compression(flate2::Compression::new(level))
    }

    pub fn none() -> Compression {
        Compression(flate2::Compression::none())
    }

    pub fn best() -> Compression {
        Compression(flate2::Compression::best())
    }
}

impl Default for Compression {

    fn default() -> Compression {
        Compression(flate2::Compression::new(5))
    }
}

/// Encodes the given iterator over protobuf messages into the gzchunked format.
///
/// This is a streaming encoder that lazily encodes the data and can be used to
/// effectively process megabytes of data. The function returns an iterator that
/// yields parts of the gzchunked file.
///
/// This variant uses default encoding settings. To customize them, one can use
/// the [`encode_with_opts`] function.
///
/// [`encode_with_opts`]: fn.encode_with_opts.html
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
/// use std::io::Write as _;
///
/// let items = vec! {
///     String::from("foo"),
///     String::from("bar"),
///     String::from("baz"),
/// };
///
/// let chunks = rrg::gzchunked::encode(items.into_iter());
/// for (idx, chunk) in chunks.enumerate() {
///     let mut file = File::open(format!("output.gzc.{}", idx)).unwrap();
///     file.write_all(chunk.unwrap().as_slice());
/// }
/// ```
pub fn encode<I, M>(iter: I) -> Encode<I>
where
    I: Iterator<Item=M>,
    M: prost::Message,
{
    encode_with_opts(iter, EncodeOpts::default())
}

/// Encodes the given iterator over protobuf messages into the gzchunked format.
///
/// This is a variant of the [`encode`] function that allows customization of
/// encoding parameters. Refer to its documentation for more details.
///
/// [`encode`]: fn.encode.html
pub fn encode_with_opts<I, M>(iter: I, opts: EncodeOpts) -> Encode<I>
where
    I: Iterator<Item=M>,
    M: prost::Message,
{
    Encode::with_opts(iter, opts)
}

/// Options and flags that configure encoding into the gzchuned format.
#[derive(Clone, Copy, Debug)]
pub struct EncodeOpts {
    /// Compression level used for the gzip encoding.
    pub compression: Compression,
    /// A rough file size limit for parts of the output file.
    pub part_size: u64,
}

impl Default for EncodeOpts {

    fn default() -> EncodeOpts {
        EncodeOpts {
            compression: Compression::default(),
            part_size: 1 * 1024 * 1024, // 1 MiB.
        }
    }
}

/// Streaming encoder for the gzchunked format.
///
/// It implements the `Iterator` trait, lazily polling the underlying iterator
/// over Protocol Buffers messages as more parts are needed.
///
/// Instances of this type can be constructed using the [`encode_with_opts`] or
/// [`encode`] function.
///
/// [`encode`]: fn.encode.html
/// [`encode_with_opts`]: fn.encode_with_opts.html
pub struct Encode<I> {
    chunked: crate::chunked::Encode<I>,
    opts: EncodeOpts,
}

impl<I> Encode<I>
where
    I: Iterator,
    I::Item: prost::Message,
{
    /// Creates a new encoder instance with the specified options.
    fn with_opts(iter: I, opts: EncodeOpts) -> Encode<I> {
        Encode {
            chunked: crate::chunked::encode(iter),
            opts: opts,
        }
    }

    /// Obtains the next part of the output file (if available).
    fn next_part(&mut self) -> std::io::Result<Option<Vec<u8>>> {
        use crate::io::copy_until;

        let compression = self.opts.compression.0;
        let part_size = self.opts.part_size;

        let mut encoder = flate2::write::GzEncoder::new(vec!(), compression);
        let len = copy_until(&mut self.chunked, &mut encoder, |_, encoder| {
            encoder.get_ref().len() as u64 >= part_size
        })?;

        if len == 0 {
            Ok(None)
        } else {
            Ok(Some(encoder.finish()?))
        }
    }
}

impl<I> Iterator for Encode<I>
where
    I: Iterator,
    I::Item: prost::Message,
{
    type Item = std::io::Result<Vec<u8>>;

    fn next(&mut self) -> Option<std::io::Result<Vec<u8>>> {
        self.next_part().transpose()
    }
}
<commit_msg>Write docs for gzchunked compression descriptor.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

/// A wrapper type for gzip compression level.
#[derive(Clone, Copy, Debug)]
pub struct Compression(flate2::Compression);

/// A type for defining gzip compression level for gzchunked.
impl Compression {

    /// Creates a new compression descriptor at the specified level.
    ///
    /// The lower the number the worse the compression (with 0 meaning no
    /// compression at all).
    pub fn new(level: u32) -> Compression {
        Compression(flate2::Compression::new(level))
    }

    /// Creates a new compression descriptor with disabled compression.
    pub fn none() -> Compression {
        Compression(flate2::Compression::none())
    }

    /// Creates a new compression descriptor with highest compression.
    pub fn best() -> Compression {
        Compression(flate2::Compression::best())
    }
}

impl Default for Compression {

    fn default() -> Compression {
        Compression(flate2::Compression::new(5))
    }
}

/// Encodes the given iterator over protobuf messages into the gzchunked format.
///
/// This is a streaming encoder that lazily encodes the data and can be used to
/// effectively process megabytes of data. The function returns an iterator that
/// yields parts of the gzchunked file.
///
/// This variant uses default encoding settings. To customize them, one can use
/// the [`encode_with_opts`] function.
///
/// [`encode_with_opts`]: fn.encode_with_opts.html
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
/// use std::io::Write as _;
///
/// let items = vec! {
///     String::from("foo"),
///     String::from("bar"),
///     String::from("baz"),
/// };
///
/// let chunks = rrg::gzchunked::encode(items.into_iter());
/// for (idx, chunk) in chunks.enumerate() {
///     let mut file = File::open(format!("output.gzc.{}", idx)).unwrap();
///     file.write_all(chunk.unwrap().as_slice());
/// }
/// ```
pub fn encode<I, M>(iter: I) -> Encode<I>
where
    I: Iterator<Item=M>,
    M: prost::Message,
{
    encode_with_opts(iter, EncodeOpts::default())
}

/// Encodes the given iterator over protobuf messages into the gzchunked format.
///
/// This is a variant of the [`encode`] function that allows customization of
/// encoding parameters. Refer to its documentation for more details.
///
/// [`encode`]: fn.encode.html
pub fn encode_with_opts<I, M>(iter: I, opts: EncodeOpts) -> Encode<I>
where
    I: Iterator<Item=M>,
    M: prost::Message,
{
    Encode::with_opts(iter, opts)
}

/// Options and flags that configure encoding into the gzchuned format.
#[derive(Clone, Copy, Debug)]
pub struct EncodeOpts {
    /// Compression level used for the gzip encoding.
    pub compression: Compression,
    /// A rough file size limit for parts of the output file.
    pub part_size: u64,
}

impl Default for EncodeOpts {

    fn default() -> EncodeOpts {
        EncodeOpts {
            compression: Compression::default(),
            part_size: 1 * 1024 * 1024, // 1 MiB.
        }
    }
}

/// Streaming encoder for the gzchunked format.
///
/// It implements the `Iterator` trait, lazily polling the underlying iterator
/// over Protocol Buffers messages as more parts are needed.
///
/// Instances of this type can be constructed using the [`encode_with_opts`] or
/// [`encode`] function.
///
/// [`encode`]: fn.encode.html
/// [`encode_with_opts`]: fn.encode_with_opts.html
pub struct Encode<I> {
    chunked: crate::chunked::Encode<I>,
    opts: EncodeOpts,
}

impl<I> Encode<I>
where
    I: Iterator,
    I::Item: prost::Message,
{
    /// Creates a new encoder instance with the specified options.
    fn with_opts(iter: I, opts: EncodeOpts) -> Encode<I> {
        Encode {
            chunked: crate::chunked::encode(iter),
            opts: opts,
        }
    }

    /// Obtains the next part of the output file (if available).
    fn next_part(&mut self) -> std::io::Result<Option<Vec<u8>>> {
        use crate::io::copy_until;

        let compression = self.opts.compression.0;
        let part_size = self.opts.part_size;

        let mut encoder = flate2::write::GzEncoder::new(vec!(), compression);
        let len = copy_until(&mut self.chunked, &mut encoder, |_, encoder| {
            encoder.get_ref().len() as u64 >= part_size
        })?;

        if len == 0 {
            Ok(None)
        } else {
            Ok(Some(encoder.finish()?))
        }
    }
}

impl<I> Iterator for Encode<I>
where
    I: Iterator,
    I::Item: prost::Message,
{
    type Item = std::io::Result<Vec<u8>>;

    fn next(&mut self) -> Option<std::io::Result<Vec<u8>>> {
        self.next_part().transpose()
    }
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://docs.rs/prost-types/0.6.1")]

//! Protocol Buffers well-known types.
//!
//! Note that the documentation for the types defined in this crate are generated from the Protobuf
//! definitions, so code examples are not in Rust.
//!
//! See the [Protobuf reference][1] for more information about well-known types.
//!
//! [1]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf

#![cfg_attr(not(feature = "std"), no_std)]

use core::convert::TryFrom;
use core::i32;
use core::i64;
use core::time;

include!("protobuf.rs");
pub mod compiler {
    include!("compiler.rs");
}

// The Protobuf `Duration` and `Timestamp` types can't delegate to the standard library equivalents
// because the Protobuf versions are signed. To make them easier to work with, `From` conversions
// are defined in both directions.

const NANOS_PER_SECOND: i32 = 1_000_000_000;

impl Duration {
    /// Normalizes the duration to a canonical format.
    ///
    /// Based on [`google::protobuf::util::CreateNormalized`][1].
    /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L79-L100
    pub fn normalize(&mut self) {
        // Make sure nanos is in the range.
        if self.nanos <= -NANOS_PER_SECOND || self.nanos >= NANOS_PER_SECOND {
            self.seconds += (self.nanos / NANOS_PER_SECOND) as i64;
            self.nanos %= NANOS_PER_SECOND;
        }

        // nanos should have the same sign as seconds.
        if self.seconds < 0 && self.nanos > 0 {
            self.seconds += 1;
            self.nanos -= NANOS_PER_SECOND;
        } else if self.seconds > 0 && self.nanos < 0 {
            self.seconds -= 1;
            self.nanos += NANOS_PER_SECOND;
        }
        // TODO: should this be checked?
        // debug_assert!(self.seconds >= -315_576_000_000 && self.seconds <= 315_576_000_000,
        //               "invalid duration: {:?}", self);
    }
}

/// Converts a `std::time::Duration` to a `Duration`.
impl From<time::Duration> for Duration {
    fn from(duration: time::Duration) -> Duration {
        let seconds = duration.as_secs();
        let seconds = if seconds > i64::MAX as u64 {
            i64::MAX
        } else {
            seconds as i64
        };
        let nanos = duration.subsec_nanos();
        let nanos = if nanos > i32::MAX as u32 {
            i32::MAX
        } else {
            nanos as i32
        };
        let mut duration = Duration { seconds, nanos };
        duration.normalize();
        duration
    }
}

impl TryFrom<Duration> for time::Duration {
    type Error = time::Duration;

    /// Converts a `Duration` to a result containing a positive (`Ok`) or negative (`Err`)
    /// `std::time::Duration`.
    fn try_from(mut duration: Duration) -> Result<time::Duration, time::Duration> {
        duration.normalize();
        if duration.seconds >= 0 {
            Ok(time::Duration::new(
                duration.seconds as u64,
                duration.nanos as u32,
            ))
        } else {
            Err(time::Duration::new(
                (-duration.seconds) as u64,
                (-duration.nanos) as u32,
            ))
        }
    }
}

impl Timestamp {
    /// Normalizes the timestamp to a canonical format.
    ///
    /// Based on [`google::protobuf::util::CreateNormalized`][1].
    /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L59-L77
    #[cfg(feature = "std")]
    pub fn normalize(&mut self) {
        // Make sure nanos is in the range.
        if self.nanos <= -NANOS_PER_SECOND || self.nanos >= NANOS_PER_SECOND {
            self.seconds += (self.nanos / NANOS_PER_SECOND) as i64;
            self.nanos %= NANOS_PER_SECOND;
        }

        // For Timestamp nanos should be in the range [0, 999999999].
        if self.nanos < 0 {
            self.seconds -= 1;
            self.nanos += NANOS_PER_SECOND;
        }

        // TODO: should this be checked?
        // debug_assert!(self.seconds >= -62_135_596_800 && self.seconds <= 253_402_300_799,
        //               "invalid timestamp: {:?}", self);
    }
}

#[cfg(feature = "std")]
impl From<std::time::SystemTime> for Timestamp {
    fn from(system_time: std::time::SystemTime) -> Timestamp {
        let (seconds, nanos) = match system_time.duration_since(std::time::UNIX_EPOCH) {
            Ok(duration) => {
                let seconds = i64::try_from(duration.as_secs()).unwrap();
                (seconds, duration.subsec_nanos() as i32)
            }
            Err(error) => {
                let duration = error.duration();
                let seconds = i64::try_from(duration.as_secs()).unwrap();
                let nanos = duration.subsec_nanos() as i32;
                if nanos == 0 {
                    (-seconds, 0)
                } else {
                    (-seconds - 1, 1_000_000_000 - nanos)
                }
            }
        };
        Timestamp { seconds, nanos }
    }
}

#[cfg(feature = "std")]
impl From<Timestamp> for std::time::SystemTime {
    fn from(mut timestamp: Timestamp) -> std::time::SystemTime {
        timestamp.normalize();
        let system_time = if timestamp.seconds >= 0 {
            std::time::UNIX_EPOCH + time::Duration::from_secs(timestamp.seconds as u64)
        } else {
            std::time::UNIX_EPOCH - time::Duration::from_secs((-timestamp.seconds) as u64)
        };

        system_time + time::Duration::from_nanos(timestamp.nanos as u64)
    }
}

#[cfg(test)]
mod tests {
    use std::time::SystemTime;

    use proptest::prelude::*;

    use super::*;

    #[cfg(feature = "std")]
    proptest! {
        #[test]
        fn check_system_time_roundtrip(
            system_time in SystemTime::arbitrary(),
        ) {
            prop_assert_eq!(SystemTime::from(Timestamp::from(system_time)), system_time);
        }
    }
}
<commit_msg>Validate Timestamp conversion from SystemTimes before UTC Epoch time<commit_after>#![doc(html_root_url = "https://docs.rs/prost-types/0.6.1")]

//! Protocol Buffers well-known types.
//!
//! Note that the documentation for the types defined in this crate are generated from the Protobuf
//! definitions, so code examples are not in Rust.
//!
//! See the [Protobuf reference][1] for more information about well-known types.
//!
//! [1]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf

#![cfg_attr(not(feature = "std"), no_std)]

use core::convert::TryFrom;
use core::i32;
use core::i64;
use core::time;

include!("protobuf.rs");
pub mod compiler {
    include!("compiler.rs");
}

// The Protobuf `Duration` and `Timestamp` types can't delegate to the standard library equivalents
// because the Protobuf versions are signed. To make them easier to work with, `From` conversions
// are defined in both directions.

const NANOS_PER_SECOND: i32 = 1_000_000_000;

impl Duration {
    /// Normalizes the duration to a canonical format.
    ///
    /// Based on [`google::protobuf::util::CreateNormalized`][1].
    /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L79-L100
    pub fn normalize(&mut self) {
        // Make sure nanos is in the range.
        if self.nanos <= -NANOS_PER_SECOND || self.nanos >= NANOS_PER_SECOND {
            self.seconds += (self.nanos / NANOS_PER_SECOND) as i64;
            self.nanos %= NANOS_PER_SECOND;
        }

        // nanos should have the same sign as seconds.
        if self.seconds < 0 && self.nanos > 0 {
            self.seconds += 1;
            self.nanos -= NANOS_PER_SECOND;
        } else if self.seconds > 0 && self.nanos < 0 {
            self.seconds -= 1;
            self.nanos += NANOS_PER_SECOND;
        }
        // TODO: should this be checked?
        // debug_assert!(self.seconds >= -315_576_000_000 && self.seconds <= 315_576_000_000,
        //               "invalid duration: {:?}", self);
    }
}

/// Converts a `std::time::Duration` to a `Duration`.
impl From<time::Duration> for Duration {
    fn from(duration: time::Duration) -> Duration {
        let seconds = duration.as_secs();
        let seconds = if seconds > i64::MAX as u64 {
            i64::MAX
        } else {
            seconds as i64
        };
        let nanos = duration.subsec_nanos();
        let nanos = if nanos > i32::MAX as u32 {
            i32::MAX
        } else {
            nanos as i32
        };
        let mut duration = Duration { seconds, nanos };
        duration.normalize();
        duration
    }
}

impl TryFrom<Duration> for time::Duration {
    type Error = time::Duration;

    /// Converts a `Duration` to a result containing a positive (`Ok`) or negative (`Err`)
    /// `std::time::Duration`.
    fn try_from(mut duration: Duration) -> Result<time::Duration, time::Duration> {
        duration.normalize();
        if duration.seconds >= 0 {
            Ok(time::Duration::new(
                duration.seconds as u64,
                duration.nanos as u32,
            ))
        } else {
            Err(time::Duration::new(
                (-duration.seconds) as u64,
                (-duration.nanos) as u32,
            ))
        }
    }
}

impl Timestamp {
    /// Normalizes the timestamp to a canonical format.
    ///
    /// Based on [`google::protobuf::util::CreateNormalized`][1].
    /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L59-L77
    #[cfg(feature = "std")]
    pub fn normalize(&mut self) {
        // Make sure nanos is in the range.
        if self.nanos <= -NANOS_PER_SECOND || self.nanos >= NANOS_PER_SECOND {
            self.seconds += (self.nanos / NANOS_PER_SECOND) as i64;
            self.nanos %= NANOS_PER_SECOND;
        }

        // For Timestamp nanos should be in the range [0, 999999999].
        if self.nanos < 0 {
            self.seconds -= 1;
            self.nanos += NANOS_PER_SECOND;
        }

        // TODO: should this be checked?
        // debug_assert!(self.seconds >= -62_135_596_800 && self.seconds <= 253_402_300_799,
        //               "invalid timestamp: {:?}", self);
    }
}

#[cfg(feature = "std")]
impl From<std::time::SystemTime> for Timestamp {
    fn from(system_time: std::time::SystemTime) -> Timestamp {
        let (seconds, nanos) = match system_time.duration_since(std::time::UNIX_EPOCH) {
            Ok(duration) => {
                let seconds = i64::try_from(duration.as_secs()).unwrap();
                (seconds, duration.subsec_nanos() as i32)
            }
            Err(error) => {
                let duration = error.duration();
                let seconds = i64::try_from(duration.as_secs()).unwrap();
                let nanos = duration.subsec_nanos() as i32;
                if nanos == 0 {
                    (-seconds, 0)
                } else {
                    (-seconds - 1, 1_000_000_000 - nanos)
                }
            }
        };
        Timestamp { seconds, nanos }
    }
}

#[cfg(feature = "std")]
impl From<Timestamp> for std::time::SystemTime {
    fn from(mut timestamp: Timestamp) -> std::time::SystemTime {
        timestamp.normalize();
        let system_time = if timestamp.seconds >= 0 {
            std::time::UNIX_EPOCH + time::Duration::from_secs(timestamp.seconds as u64)
        } else {
            std::time::UNIX_EPOCH - time::Duration::from_secs((-timestamp.seconds) as u64)
        };

        system_time + time::Duration::from_nanos(timestamp.nanos as u64)
    }
}

#[cfg(test)]
mod tests {
    use std::time::{Duration, SystemTime, UNIX_EPOCH};

    use proptest::prelude::*;

    use super::*;

    #[cfg(feature = "std")]
    proptest! {
        #[test]
        fn check_system_time_roundtrip(
            system_time in SystemTime::arbitrary(),
        ) {
            prop_assert_eq!(SystemTime::from(Timestamp::from(system_time)), system_time);
        }
    }

    #[cfg(feature = "std")]
    #[test]
    fn check_timestamp_negative_seconds() {
        // Representative tests for the case of timestamps before the UTC Epoch time:
        // validate the expected behaviour that "negative second values with fractions
        // must still have non-negative nanos values that count forward in time"
        // https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp
        //
        // To ensure cross-platform compatibility, all nanosecond values in these
        // tests are in minimum 100 ns increments.  This does not affect the general
        // character of the behaviour being tested, but ensures that the tests are
        // valid for both POSIX (1 ns precision) and Windows (100 ns precision).
        assert_eq!(
            Timestamp::from(UNIX_EPOCH - Duration::new(1_001, 0)),
            Timestamp {
                seconds: -1_001,
                nanos: 0
            }
        );
        assert_eq!(
            Timestamp::from(UNIX_EPOCH - Duration::new(0, 999_999_900)),
            Timestamp {
                seconds: -1,
                nanos: 100
            }
        );
        assert_eq!(
            Timestamp::from(UNIX_EPOCH - Duration::new(2_001_234, 12_300)),
            Timestamp {
                seconds: -2_001_235,
                nanos: 999_987_700
            }
        );
        assert_eq!(
            Timestamp::from(UNIX_EPOCH - Duration::new(768, 65_432_100)),
            Timestamp {
                seconds: -769,
                nanos: 934_567_900
            }
        );
    }

    #[cfg(all(unix, feature = "std"))]
    #[test]
    fn check_timestamp_negative_seconds_1ns() {
        // UNIX-only test cases with 1 ns precision
        assert_eq!(
            Timestamp::from(UNIX_EPOCH - Duration::new(0, 999_999_999)),
            Timestamp {
                seconds: -1,
                nanos: 1
            }
        );
        assert_eq!(
            Timestamp::from(UNIX_EPOCH - Duration::new(1_234_567, 123)),
            Timestamp {
                seconds: -1_234_568,
                nanos: 999_999_877
            }
        );
        assert_eq!(
            Timestamp::from(UNIX_EPOCH - Duration::new(890, 987_654_321)),
            Timestamp {
                seconds: -891,
                nanos: 12_345_679
            }
        );
    }
}
<|endoftext|>


<commit_before>const CODE_MAX_SIZE: usize = 8192 * 2 * 2;
const CODE_MAX_DATA: usize = 8192 * 2;

const OP_VAL_INCR: u8 = 1;
const OP_VAL_DECR: u8 = 2;
const OP_PNT_INCR: u8 = 3;
const OP_PNT_DECR: u8 = 4;
const OP_LOOP_START: u8 = 5;
const OP_LOOP_END: u8 = 6;
const OP_OUT: u8 = 7;
const OP_IN: u8 = 8;
const OP_END: u8 = 9;

#[derive(Copy, Clone)]
pub struct Operation {
    op: u8,
    ex: u32
}

pub struct Program {
    pc: usize,
    ptr: usize,
    data: [u32; CODE_MAX_DATA],
    code: [Operation; CODE_MAX_SIZE]
}

impl Program {
    pub fn new() -> Program
    {
        Program {
            pc: 0,
            ptr: 0,
            data: [0u32; CODE_MAX_DATA],
            code: [Operation { op: 0u8, ex: 0u32}; CODE_MAX_SIZE]
        }
    }

    pub fn set(&mut self, location: usize, operation: Operation)
    {
        self.code[location] = operation;
    }

    pub fn get(&mut self, location: usize) -> Operation
    {
        self.code[location]
    }

    fn reset(&mut self)
    {
        self.pc = 0;
        self.ptr = 0;
        self.data = [0u32; CODE_MAX_DATA];
    }

    pub fn run(&mut self)
    {
        self.reset();
        while self.code[self.pc].op != OP_END {
            match self.code[self.pc].op {
                OP_VAL_INCR => self.data[self.ptr] += 1,
                OP_VAL_DECR => if self.data[self.ptr] > 0 { self.data[self.ptr] -= 1 },
                OP_PNT_INCR => self.ptr += 1,
                OP_PNT_DECR => if self.ptr > 0 { self.ptr -= 1 },
                OP_LOOP_START => {
                    if self.data[self.ptr] == 0 {
                        self.pc = self.code[self.pc].ex as usize;
                    }
                },
                OP_LOOP_END => {
                    if self.data[self.ptr] > 0 {
                        self.pc = self.code[self.pc].ex as usize;
                    }
                },
                OP_OUT => {
                    print!("{}", self.data[self.ptr] as u8 as char);
                }
                _ => {}
            }

            self.pc += 1;
        }
    }

    pub fn debug(&mut self)
    {
        self.reset();
        while self.code[self.pc].op != OP_END {
            match self.code[self.pc].op {
                OP_VAL_INCR => print!("{}: \t+\n", self.pc),
                OP_VAL_DECR => print!("{}: \t-\n", self.pc),
                OP_PNT_INCR => print!("{}: \t>\n", self.pc),
                OP_PNT_DECR => print!("{}: \t<\n", self.pc),
                OP_LOOP_START => {
                    print!("{}: \t[ \t{} \t{}\n", self.pc, self.data[self.ptr], self.code[self.pc].ex);
                },
                OP_LOOP_END => {
                    print!("{}: \t] \t{} \t{}\n", self.pc, self.data[self.ptr], self.code[self.pc].ex);
                },
                OP_OUT => {
                    print!("{}: \t.\n", self.pc)
                }
                _ => {}
            }

            self.pc += 1;
        }
    }
}

pub struct BrainfuckParser;
impl BrainfuckParser {
    pub fn parse(codestring: &str, program: &mut Program)
    {
        // Current program pointer
        let mut pc = 0usize;

        // Stack(Vector) used for loops
        let mut stack: Vec<usize> = Vec::new();

        for c in codestring.chars() {
            match c {
                '+' => program.set(pc, Operation { op: OP_VAL_INCR, ex: 1 }),
                '-' => program.set(pc, Operation { op: OP_VAL_DECR, ex: 1 }),
                '>' => program.set(pc, Operation { op: OP_PNT_INCR, ex: 1 }),
                '<' => program.set(pc, Operation { op: OP_PNT_DECR, ex: 1 }),
                '[' => {
                    program.set(pc, Operation { op: OP_LOOP_START, ex: 0 });
                    stack.push(pc);
                    },
                ']' => {
                    let pc_jmp = match stack.pop() {
                        None => break, // empty
                        Some(x) => x,
                    };
                    program.set(pc, Operation { op: OP_LOOP_END, ex: pc_jmp as u32 });
                    let mut op = program.get(pc_jmp);
                    op.ex = pc as u32;
                    program.set(pc_jmp, op);
                    },
                '.' => program.set(pc, Operation { op: OP_OUT, ex: 0 }),
                ',' => program.set(pc, Operation { op: OP_IN, ex: 0 }),
                _ => {
                    if pc > 0 {
                        pc = pc - 1
                    }
                },
            };

            pc = pc + 1;
        }
        program.set(pc, Operation { op: OP_END, ex: 0});
    }

}
<commit_msg>+ Increased array size<commit_after>const CODE_MAX_SIZE: usize = 1024 * 64;
const CODE_MAX_DATA: usize = 1024 * 32;

const OP_VAL_INCR: u8 = 1;
const OP_VAL_DECR: u8 = 2;
const OP_PNT_INCR: u8 = 3;
const OP_PNT_DECR: u8 = 4;
const OP_LOOP_START: u8 = 5;
const OP_LOOP_END: u8 = 6;
const OP_OUT: u8 = 7;
const OP_IN: u8 = 8;
const OP_END: u8 = 9;

#[derive(Copy, Clone)]
pub struct Operation {
    op: u8,
    ex: u32
}

pub struct Program {
    pc: usize,
    ptr: usize,
    data: [u32; CODE_MAX_DATA],
    code: [Operation; CODE_MAX_SIZE]
}

impl Program {
    pub fn new() -> Program
    {
        Program {
            pc: 0,
            ptr: 0,
            data: [0u32; CODE_MAX_DATA],
            code: [Operation { op: 0u8, ex: 0u32}; CODE_MAX_SIZE]
        }
    }

    pub fn set(&mut self, location: usize, operation: Operation)
    {
        self.code[location] = operation;
    }

    pub fn get(&mut self, location: usize) -> Operation
    {
        self.code[location]
    }

    fn reset(&mut self)
    {
        self.pc = 0;
        self.ptr = 0;
        self.data = [0u32; CODE_MAX_DATA];
    }

    pub fn run(&mut self)
    {
        self.reset();
        while self.code[self.pc].op != OP_END {
            match self.code[self.pc].op {
                OP_VAL_INCR => self.data[self.ptr] += 1,
                OP_VAL_DECR => if self.data[self.ptr] > 0 { self.data[self.ptr] -= 1 },
                OP_PNT_INCR => self.ptr += 1,
                OP_PNT_DECR => if self.ptr > 0 { self.ptr -= 1 },
                OP_LOOP_START => {
                    if self.data[self.ptr] == 0 {
                        self.pc = self.code[self.pc].ex as usize;
                    }
                },
                OP_LOOP_END => {
                    if self.data[self.ptr] > 0 {
                        self.pc = self.code[self.pc].ex as usize;
                    }
                },
                OP_OUT => {
                    print!("{}", self.data[self.ptr] as u8 as char);
                }
                _ => {}
            }

            self.pc += 1;
        }
    }

    pub fn debug(&mut self)
    {
        self.reset();
        while self.code[self.pc].op != OP_END {
            match self.code[self.pc].op {
                OP_VAL_INCR => print!("{}: \t+\n", self.pc),
                OP_VAL_DECR => print!("{}: \t-\n", self.pc),
                OP_PNT_INCR => print!("{}: \t>\n", self.pc),
                OP_PNT_DECR => print!("{}: \t<\n", self.pc),
                OP_LOOP_START => {
                    print!("{}: \t[ \t{} \t{}\n", self.pc, self.data[self.ptr], self.code[self.pc].ex);
                },
                OP_LOOP_END => {
                    print!("{}: \t] \t{} \t{}\n", self.pc, self.data[self.ptr], self.code[self.pc].ex);
                },
                OP_OUT => {
                    print!("{}: \t.\n", self.pc)
                }
                _ => {}
            }

            self.pc += 1;
        }
    }
}

pub struct BrainfuckParser;
impl BrainfuckParser {
    pub fn parse(codestring: &str, program: &mut Program)
    {
        // Current program pointer
        let mut pc = 0usize;

        // Stack(Vector) used for loops
        let mut stack: Vec<usize> = Vec::new();

        for c in codestring.chars() {
            match c {
                '+' => program.set(pc, Operation { op: OP_VAL_INCR, ex: 1 }),
                '-' => program.set(pc, Operation { op: OP_VAL_DECR, ex: 1 }),
                '>' => program.set(pc, Operation { op: OP_PNT_INCR, ex: 1 }),
                '<' => program.set(pc, Operation { op: OP_PNT_DECR, ex: 1 }),
                '[' => {
                    program.set(pc, Operation { op: OP_LOOP_START, ex: 0 });
                    stack.push(pc);
                    },
                ']' => {
                    let pc_jmp = match stack.pop() {
                        None => break, // empty
                        Some(x) => x,
                    };
                    program.set(pc, Operation { op: OP_LOOP_END, ex: pc_jmp as u32 });
                    let mut op = program.get(pc_jmp);
                    op.ex = pc as u32;
                    program.set(pc_jmp, op);
                    },
                '.' => program.set(pc, Operation { op: OP_OUT, ex: 0 }),
                ',' => program.set(pc, Operation { op: OP_IN, ex: 0 }),
                _ => {
                    if pc > 0 {
                        pc = pc - 1
                    }
                },
            };

            pc = pc + 1;
        }
        program.set(pc, Operation { op: OP_END, ex: 0});
    }

}
<|endoftext|>


<commit_before>//! Messages to and from the server.
use std::borrow::ToOwned;
use std::io::{Result as IoResult};
use std::str::FromStr;
use client::data::Command;

/// IRC Message data.
#[derive(Clone, PartialEq, Debug)]
pub struct Message {
    /// Message tags as defined by [IRCv3.2](http://ircv3.net/specs/core/message-tags-3.2.html).
    pub tags: Option<Vec<Tag>>,
    /// The message prefix (or source) as defined by [RFC 2812](http://tools.ietf.org/html/rfc2812).
    pub prefix: Option<String>,
    /// The IRC command.
    pub command: Command,
}

impl Message {
    /// Creates a new Message.
    pub fn new(prefix: Option<&str>, command: &str, args: Vec<&str>, suffix: Option<&str>)
        -> IoResult<Message> {
        Message::with_tags(None, prefix, command, args, suffix)
    }

    /// Creates a new Message optionally including IRCv3.2 message tags.
    pub fn with_tags(tags: Option<Vec<Tag>>, prefix: Option<&str>, command: &str,
                     args: Vec<&str>, suffix: Option<&str>) -> IoResult<Message> {
        Ok(Message {
            tags: tags,
            prefix: prefix.map(|s| s.to_owned()),
            command: try!(Command::new(command, args, suffix)),
        })
    }

    /// Gets the nickname of the message source, if it exists.
    pub fn source_nickname(&self) -> Option<&str> {
        self.prefix.as_ref().and_then(|s|
            match (s.find('!'), s.find('@'), s.find('.')) {
                (_, _, Some(_)) => None,
                (Some(i), _, None) => Some(&s[..i]),
                (None, Some(i), None) => Some(&s[..i]),
                (None, None, None) => Some(&s)
            }
        )
    }

    /// Converts a Message into a String according to the IRC protocol.
    pub fn into_string(&self) -> String {
        // TODO: tags
        let mut ret = String::new();
        if let Some(ref prefix) = self.prefix {
            ret.push(':');
            ret.push_str(&prefix);
            ret.push(' ');
        }
        let cmd: String = From::from(&self.command);
        ret.push_str(&cmd);
        ret.push_str("\r\n");
        ret
    }
}

impl From<Command> for Message {
    fn from(cmd: Command) -> Message {
        Message { tags: None, prefix: None, command: cmd }
    }
}

impl FromStr for Message {
    type Err = &'static str;
    fn from_str(s: &str) -> Result<Message, &'static str> {
        let mut state = s.clone();
        if s.len() == 0 { return Err("Cannot parse an empty string as a message.") }
        let tags = if state.starts_with("@") {
            let tags = state.find(' ').map(|i| &state[1..i]);
            state = state.find(' ').map_or("", |i| &state[i+1..]);
            tags.map(|ts| ts.split(";").filter(|s| s.len() != 0).map(|s: &str| {
                let mut iter = s.splitn(2, "=");
                let (fst, snd) = (iter.next(), iter.next());
                Tag(fst.unwrap_or("").to_owned(), snd.map(|s| s.to_owned()))
            }).collect::<Vec<_>>())
        } else {
            None
        };
        let prefix = if state.starts_with(":") {
            let prefix = state.find(' ').map(|i| &state[1..i]);
            state = state.find(' ').map_or("", |i| &state[i+1..]);
            prefix
        } else {
            None
        };
        let suffix = if state.contains(" :") {
            let suffix = state.find(" :").map(|i| &state[i+2..state.len()-2]);
            state = state.find(" :").map_or("", |i| &state[..i+1]);
            suffix
        } else {
            None
        };
        let command = match state.find(' ').map(|i| &state[..i]) {
            Some(cmd) => {
                state = state.find(' ').map_or("", |i| &state[i+1..]);
                cmd
            }
            _ => return Err("Cannot parse a message without a command.")
        };
        if suffix.is_none() { state = &state[..state.len() - 2] }
        let args: Vec<_> = state.splitn(14, ' ').filter(|s| s.len() != 0).collect();
        Message::with_tags(
            tags, prefix, command, args, suffix
        ).map_err(|_| "Invalid input for Command.")
    }
}

impl<'a> From<&'a str> for Message {
    fn from(s: &'a str) -> Message {
        s.parse().unwrap()
    }
}

/// A message tag as defined by [IRCv3.2](http://ircv3.net/specs/core/message-tags-3.2.html).
#[derive(Clone, PartialEq, Debug)]
pub struct Tag(String, Option<String>);

#[cfg(test)]
mod test {
    use super::{Message, Tag};
    use client::data::Command::{PRIVMSG, Raw};

    #[test]
    fn new() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        assert_eq!(Message::new(None, "PRIVMSG", vec!["test"], Some("Testing!")).unwrap(), message)
    }

    #[test]
    fn source_nickname() {
        assert_eq!(Message::new(
            None, "PING", vec![], Some("data")
        ).unwrap().source_nickname(), None);
        assert_eq!(Message::new(
            Some("irc.test.net"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), None);
        assert_eq!(Message::new(
            Some("test!test@test"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));
        assert_eq!(Message::new(
            Some("test@test"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));
        assert_eq!(Message::new(
            Some("test"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));
    }

    #[test]
    fn into_string() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        assert_eq!(&message.into_string()[..], "PRIVMSG test :Testing!\r\n");
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Still testing!")),
        };
        assert_eq!(&message.into_string()[..], ":test!test@test PRIVMSG test :Still testing!\r\n");
    }

    #[test]
    fn from_string() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        assert_eq!("PRIVMSG test :Testing!\r\n".parse(), Ok(message));
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Still testing!")),
        };
        assert_eq!(":test!test@test PRIVMSG test :Still testing!\r\n".parse(), Ok(message));
        let message = Message {
            tags: Some(vec![Tag(format!("aaa"), Some(format!("bbb"))),
                            Tag(format!("ccc"), None),
                            Tag(format!("example.com/ddd"), Some(format!("eee")))]),
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Testing with tags!")),
        };
        assert_eq!("@aaa=bbb;ccc;example.com/ddd=eee :test!test@test PRIVMSG test :Testing with \
                    tags!\r\n".parse(), Ok(message))
    }

    #[test]
    fn to_message() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        let msg: Message = "PRIVMSG test :Testing!\r\n".into();
        assert_eq!(msg, message);
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Still testing!")),
        };
        let msg: Message = ":test!test@test PRIVMSG test :Still testing!\r\n".into();
        assert_eq!(msg, message);
    }

    #[test]
    fn to_message_with_colon_in_arg() {
        // Apparently, UnrealIRCd (and perhaps some others) send some messages that include
        // colons within individual parameters. So, let's make sure it parses correctly.
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: Raw(
                format!("COMMAND"), vec![format!("ARG:test")], Some(format!("Testing!"))
            ),
        };
        let msg: Message = ":test!test@test COMMAND ARG:test :Testing!\r\n".into();
        assert_eq!(msg, message);
    }

    #[test]
    #[should_panic]
    fn to_message_invalid_format() {
        let _: Message = ":invalid :message".into();
    }
}
<commit_msg>User idents and hostnames actually can have dots<commit_after>//! Messages to and from the server.
use std::borrow::ToOwned;
use std::io::{Result as IoResult};
use std::str::FromStr;
use client::data::Command;

/// IRC Message data.
#[derive(Clone, PartialEq, Debug)]
pub struct Message {
    /// Message tags as defined by [IRCv3.2](http://ircv3.net/specs/core/message-tags-3.2.html).
    pub tags: Option<Vec<Tag>>,
    /// The message prefix (or source) as defined by [RFC 2812](http://tools.ietf.org/html/rfc2812).
    pub prefix: Option<String>,
    /// The IRC command.
    pub command: Command,
}

impl Message {
    /// Creates a new Message.
    pub fn new(prefix: Option<&str>, command: &str, args: Vec<&str>, suffix: Option<&str>)
        -> IoResult<Message> {
        Message::with_tags(None, prefix, command, args, suffix)
    }

    /// Creates a new Message optionally including IRCv3.2 message tags.
    pub fn with_tags(tags: Option<Vec<Tag>>, prefix: Option<&str>, command: &str,
                     args: Vec<&str>, suffix: Option<&str>) -> IoResult<Message> {
        Ok(Message {
            tags: tags,
            prefix: prefix.map(|s| s.to_owned()),
            command: try!(Command::new(command, args, suffix)),
        })
    }

    /// Gets the nickname of the message source, if it exists.
    pub fn source_nickname(&self) -> Option<&str> {
        self.prefix.as_ref().and_then(|s|
            match (s.find('!'), s.find('@'), s.find('.')) {
                (_, _, Some(_)) => None,
                (Some(i), _, None) => Some(&s[..i]),
                (None, Some(i), None) => Some(&s[..i]),
                (None, None, None) => Some(&s)
            }
        )
    }

    /// Converts a Message into a String according to the IRC protocol.
    pub fn into_string(&self) -> String {
        // TODO: tags
        let mut ret = String::new();
        if let Some(ref prefix) = self.prefix {
            ret.push(':');
            ret.push_str(&prefix);
            ret.push(' ');
        }
        let cmd: String = From::from(&self.command);
        ret.push_str(&cmd);
        ret.push_str("\r\n");
        ret
    }
}

impl From<Command> for Message {
    fn from(cmd: Command) -> Message {
        Message { tags: None, prefix: None, command: cmd }
    }
}

impl FromStr for Message {
    type Err = &'static str;
    fn from_str(s: &str) -> Result<Message, &'static str> {
        let mut state = s.clone();
        if s.len() == 0 { return Err("Cannot parse an empty string as a message.") }
        let tags = if state.starts_with("@") {
            let tags = state.find(' ').map(|i| &state[1..i]);
            state = state.find(' ').map_or("", |i| &state[i+1..]);
            tags.map(|ts| ts.split(";").filter(|s| s.len() != 0).map(|s: &str| {
                let mut iter = s.splitn(2, "=");
                let (fst, snd) = (iter.next(), iter.next());
                Tag(fst.unwrap_or("").to_owned(), snd.map(|s| s.to_owned()))
            }).collect::<Vec<_>>())
        } else {
            None
        };
        let prefix = if state.starts_with(":") {
            let prefix = state.find(' ').map(|i| &state[1..i]);
            state = state.find(' ').map_or("", |i| &state[i+1..]);
            prefix
        } else {
            None
        };
        let suffix = if state.contains(" :") {
            let suffix = state.find(" :").map(|i| &state[i+2..state.len()-2]);
            state = state.find(" :").map_or("", |i| &state[..i+1]);
            suffix
        } else {
            None
        };
        let command = match state.find(' ').map(|i| &state[..i]) {
            Some(cmd) => {
                state = state.find(' ').map_or("", |i| &state[i+1..]);
                cmd
            }
            _ => return Err("Cannot parse a message without a command.")
        };
        if suffix.is_none() { state = &state[..state.len() - 2] }
        let args: Vec<_> = state.splitn(14, ' ').filter(|s| s.len() != 0).collect();
        Message::with_tags(
            tags, prefix, command, args, suffix
        ).map_err(|_| "Invalid input for Command.")
    }
}

impl<'a> From<&'a str> for Message {
    fn from(s: &'a str) -> Message {
        s.parse().unwrap()
    }
}

/// A message tag as defined by [IRCv3.2](http://ircv3.net/specs/core/message-tags-3.2.html).
#[derive(Clone, PartialEq, Debug)]
pub struct Tag(String, Option<String>);

#[cfg(test)]
mod test {
    use super::{Message, Tag};
    use client::data::Command::{PRIVMSG, Raw};

    #[test]
    fn new() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        assert_eq!(Message::new(None, "PRIVMSG", vec!["test"], Some("Testing!")).unwrap(), message)
    }

    #[test]
    fn source_nickname() {
        assert_eq!(Message::new(
            None, "PING", vec![], Some("data")
        ).unwrap().source_nickname(), None);

        assert_eq!(Message::new(
            Some("irc.test.net"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), None);

        assert_eq!(Message::new(
            Some("test!test@test"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test@test"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test!test@awe.did.you.know.irc.hostnames.have.dots"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test!test@127.0.0.1"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test@test.com"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));
    }

    #[test]
    fn into_string() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        assert_eq!(&message.into_string()[..], "PRIVMSG test :Testing!\r\n");
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Still testing!")),
        };
        assert_eq!(&message.into_string()[..], ":test!test@test PRIVMSG test :Still testing!\r\n");
    }

    #[test]
    fn from_string() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        assert_eq!("PRIVMSG test :Testing!\r\n".parse(), Ok(message));
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Still testing!")),
        };
        assert_eq!(":test!test@test PRIVMSG test :Still testing!\r\n".parse(), Ok(message));
        let message = Message {
            tags: Some(vec![Tag(format!("aaa"), Some(format!("bbb"))),
                            Tag(format!("ccc"), None),
                            Tag(format!("example.com/ddd"), Some(format!("eee")))]),
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Testing with tags!")),
        };
        assert_eq!("@aaa=bbb;ccc;example.com/ddd=eee :test!test@test PRIVMSG test :Testing with \
                    tags!\r\n".parse(), Ok(message))
    }

    #[test]
    fn to_message() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        let msg: Message = "PRIVMSG test :Testing!\r\n".into();
        assert_eq!(msg, message);
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Still testing!")),
        };
        let msg: Message = ":test!test@test PRIVMSG test :Still testing!\r\n".into();
        assert_eq!(msg, message);
    }

    #[test]
    fn to_message_with_colon_in_arg() {
        // Apparently, UnrealIRCd (and perhaps some others) send some messages that include
        // colons within individual parameters. So, let's make sure it parses correctly.
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: Raw(
                format!("COMMAND"), vec![format!("ARG:test")], Some(format!("Testing!"))
            ),
        };
        let msg: Message = ":test!test@test COMMAND ARG:test :Testing!\r\n".into();
        assert_eq!(msg, message);
    }

    #[test]
    #[should_panic]
    fn to_message_invalid_format() {
        let _: Message = ":invalid :message".into();
    }
}
<|endoftext|>


<commit_before>pub mod protobufs;

use address::Address;

#[derive(Debug, Clone)]
pub struct TextMessage {
    pub id: Address,
    pub sender: Address,
    pub text: String
}

impl TextMessage {
    pub fn new(sender: Address, text: String) -> TextMessage {
        // TODO: Better message ID generation (UUID?)
        let id = Address::for_content(format!("{}{}", sender.to_str(), text).as_str());
        TextMessage {
            id: id,
            sender: sender,
            text: text
        }
    }

    pub fn envelope(self, recipient: Address) -> Envelope {
        Envelope {
            recipient: recipient,
            message: Message::TextMessage(self)
        }
    }
}

#[derive(Debug, Clone)]
pub struct MessageAcknowledgement {
    pub message_id: Address
}

impl MessageAcknowledgement {
    pub fn new(message_id: Address) -> MessageAcknowledgement {
        MessageAcknowledgement {
            message_id: message_id
        }
    }

    pub fn envelope(self, recipient: Address) -> Envelope {
        Envelope {
            recipient: recipient,
            message: Message::MessageAcknowledgement(self)
        }
    }
}

#[derive(Debug, Clone)]
pub enum Message {
    TextMessage(TextMessage),
    MessageAcknowledgement(MessageAcknowledgement)
}

#[derive(Debug, Clone)]
pub struct Envelope {
    pub recipient: Address,
    pub message: Message
}

impl Envelope {
    pub fn encode(self) -> Vec<u8> {
        use protobuf::Message as MessageForFunctions;
        let mut message = protobufs::Envelope::new();
        message.set_recipient(self.recipient.to_str());

        match self.message {
            Message::TextMessage(text_message) => {
                let mut encoded = protobufs::TextMessage::new();
                encoded.set_id(text_message.id.to_str());
                encoded.set_sender(text_message.sender.to_str());
                encoded.set_text(text_message.text);
                message.set_message_type(protobufs::Envelope_Type::TEXT_MESSAGE);
                message.set_text_message(encoded);
            }
            Message::MessageAcknowledgement(message_acknowledgement) => {
                let mut encoded = protobufs::MessageAcknowledgement::new();
                encoded.set_message_id(message_acknowledgement.message_id.to_str());
                message.set_message_type(protobufs::Envelope_Type::MESSAGE_ACKNOWLEDGEMENT);
                message.set_message_acknowledgement(encoded);
            }
        }

        message.write_to_bytes().unwrap()
    }
}

pub fn decode(data: Vec<u8>) -> Envelope {
    use protobuf;
    use std::io::Cursor;
    let mut data = Cursor::new(data);
    let envelope = protobuf::parse_from_reader::<protobufs::Envelope>(&mut data).unwrap();
    match envelope.get_message_type() {
        protobufs::Envelope_Type::TEXT_MESSAGE => {
            let message = envelope.get_text_message();
            Envelope {
                recipient: Address::from_str(envelope.get_recipient()),
                message: Message::TextMessage(TextMessage {
                    id: Address::from_str(message.get_id()),
                    sender: Address::from_str(message.get_sender()),
                    text: message.get_text().to_string()
                })
            }
        }
        protobufs::Envelope_Type::MESSAGE_ACKNOWLEDGEMENT => {
            let ack = envelope.get_message_acknowledgement();
            Envelope {
                recipient: Address::from_str(envelope.get_recipient()),
                message: Message::MessageAcknowledgement(MessageAcknowledgement {
                    message_id: Address::from_str(ack.get_message_id())
                })
            }
        }
    }
}
<commit_msg>Randomly generate message ID<commit_after>pub mod protobufs;

use num;
use num::bigint::ToBigUint;

use address;
use address::Address;

#[derive(Debug, Clone)]
pub struct TextMessage {
    pub id: Address,
    pub sender: Address,
    pub text: String
}

impl TextMessage {
    pub fn new(sender: Address, text: String) -> TextMessage {
        let min = 0.to_biguint().unwrap();
        let max = num::pow(2.to_biguint().unwrap(), address::LENGTH);
        let id = Address::random(&min, &max);
        TextMessage {
            id: id,
            sender: sender,
            text: text
        }
    }

    pub fn envelope(self, recipient: Address) -> Envelope {
        Envelope {
            recipient: recipient,
            message: Message::TextMessage(self)
        }
    }
}

#[derive(Debug, Clone)]
pub struct MessageAcknowledgement {
    pub message_id: Address
}

impl MessageAcknowledgement {
    pub fn new(message_id: Address) -> MessageAcknowledgement {
        MessageAcknowledgement {
            message_id: message_id
        }
    }

    pub fn envelope(self, recipient: Address) -> Envelope {
        Envelope {
            recipient: recipient,
            message: Message::MessageAcknowledgement(self)
        }
    }
}

#[derive(Debug, Clone)]
pub enum Message {
    TextMessage(TextMessage),
    MessageAcknowledgement(MessageAcknowledgement)
}

#[derive(Debug, Clone)]
pub struct Envelope {
    pub recipient: Address,
    pub message: Message
}

impl Envelope {
    pub fn encode(self) -> Vec<u8> {
        use protobuf::Message as MessageForFunctions;
        let mut message = protobufs::Envelope::new();
        message.set_recipient(self.recipient.to_str());

        match self.message {
            Message::TextMessage(text_message) => {
                let mut encoded = protobufs::TextMessage::new();
                encoded.set_id(text_message.id.to_str());
                encoded.set_sender(text_message.sender.to_str());
                encoded.set_text(text_message.text);
                message.set_message_type(protobufs::Envelope_Type::TEXT_MESSAGE);
                message.set_text_message(encoded);
            }
            Message::MessageAcknowledgement(message_acknowledgement) => {
                let mut encoded = protobufs::MessageAcknowledgement::new();
                encoded.set_message_id(message_acknowledgement.message_id.to_str());
                message.set_message_type(protobufs::Envelope_Type::MESSAGE_ACKNOWLEDGEMENT);
                message.set_message_acknowledgement(encoded);
            }
        }

        message.write_to_bytes().unwrap()
    }
}

pub fn decode(data: Vec<u8>) -> Envelope {
    use protobuf;
    use std::io::Cursor;
    let mut data = Cursor::new(data);
    let envelope = protobuf::parse_from_reader::<protobufs::Envelope>(&mut data).unwrap();
    match envelope.get_message_type() {
        protobufs::Envelope_Type::TEXT_MESSAGE => {
            let message = envelope.get_text_message();
            Envelope {
                recipient: Address::from_str(envelope.get_recipient()),
                message: Message::TextMessage(TextMessage {
                    id: Address::from_str(message.get_id()),
                    sender: Address::from_str(message.get_sender()),
                    text: message.get_text().to_string()
                })
            }
        }
        protobufs::Envelope_Type::MESSAGE_ACKNOWLEDGEMENT => {
            let ack = envelope.get_message_acknowledgement();
            Envelope {
                recipient: Address::from_str(envelope.get_recipient()),
                message: Message::MessageAcknowledgement(MessageAcknowledgement {
                    message_id: Address::from_str(ack.get_message_id())
                })
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::{hab_core,
            hab_http};
use std::{error,
          fmt,
          io,
          num,
          path::PathBuf,
          result};
use tokio::task::JoinError;

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    APIError(reqwest::StatusCode, String),
    BadResponseBody(reqwest::Error),
    DownloadWrite(PathBuf, io::Error),
    HabitatCore(hab_core::Error),
    HabitatHttpClient(hab_http::Error),
    ReqwestError(reqwest::Error),
    IO(io::Error),
    Json(serde_json::Error),
    KeyReadError(PathBuf, io::Error),
    MissingHeader(String),
    InvalidHeader(String),
    NoFilePart,
    PackageReadError(PathBuf, io::Error),
    ParseIntError(num::ParseIntError),
    IdentNotFullyQualified,
    RenderContextSerialization(serde_json::Error),
    UploadFailed(String),
    UrlParseError(url::ParseError),
    WriteSyncFailed,
    NotSupported,
    TokioJoinError(JoinError),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let msg = match *self {
            Error::APIError(ref c, ref m) if !m.is_empty() => format!("[{}] {}", c, m),
            Error::APIError(ref c, _) => format!("[{}]", c),
            Error::BadResponseBody(ref e) => format!("Failed to read response body, {}", e),
            Error::DownloadWrite(ref p, ref e) => {
                format!("Failed to write contents of builder response, {}, {}",
                        p.display(),
                        e)
            }
            Error::HabitatCore(ref e) => format!("{}", e),
            Error::HabitatHttpClient(ref e) => format!("{}", e),
            Error::ReqwestError(ref err) => format!("{}", err),
            Error::IO(ref e) => format!("{}", e),
            Error::Json(ref e) => format!("{}", e),
            Error::KeyReadError(ref p, ref e) => {
                format!("Failed to read origin key, {}, {}", p.display(), e)
            }
            Error::MissingHeader(ref s) => format!("Response is missing a required header: {}", s),
            Error::InvalidHeader(ref s) => format!("Response header is invalid: {}", s),
            Error::NoFilePart => "An invalid path was passed - we needed a filename, and this \
                                  path does not have one"
                                                         .to_string(),
            Error::PackageReadError(ref p, ref e) => {
                format!("Failed to read package artifact, {}, {}", p.display(), e)
            }
            Error::ParseIntError(ref err) => format!("{}", err),
            Error::RenderContextSerialization(ref e) => {
                format!("Unable to serialize rendering context, {}", e)
            }
            Error::IdentNotFullyQualified => {
                "Cannot perform the specified operation. Specify a fully qualifed package \
                 identifier (ex: core/busybox-static/1.42.2/20170513215502)"
                                                                            .to_string()
            }
            Error::UploadFailed(ref s) => format!("Upload failed: {}", s),
            Error::UrlParseError(ref e) => format!("{}", e),
            Error::WriteSyncFailed => {
                "Could not write to destination; perhaps the disk is full?".to_string()
            }
            Error::NotSupported => "The specified operation is not supported.".to_string(),
            Error::TokioJoinError(ref e) => format!("{}", e),
        };
        write!(f, "{}", msg)
    }
}

impl error::Error for Error {}

impl From<hab_core::Error> for Error {
    fn from(err: hab_core::Error) -> Error { Error::HabitatCore(err) }
}

impl From<hab_http::Error> for Error {
    fn from(err: hab_http::Error) -> Error { Error::HabitatHttpClient(err) }
}

impl From<reqwest::Error> for Error {
    fn from(err: reqwest::Error) -> Error { Error::ReqwestError(err) }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error { Error::IO(err) }
}

impl From<serde_json::Error> for Error {
    fn from(err: serde_json::Error) -> Error { Error::Json(err) }
}

impl From<url::ParseError> for Error {
    fn from(err: url::ParseError) -> Error { Error::UrlParseError(err) }
}

impl From<JoinError> for Error {
    fn from(err: JoinError) -> Error { Error::TokioJoinError(err) }
}
<commit_msg>removing unused Error entry for the builder-api-client<commit_after>use crate::{hab_core,
            hab_http};
use std::{error,
          fmt,
          io,
          num,
          path::PathBuf,
          result};
use tokio::task::JoinError;

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    APIError(reqwest::StatusCode, String),
    BadResponseBody(reqwest::Error),
    DownloadWrite(PathBuf, io::Error),
    HabitatCore(hab_core::Error),
    HabitatHttpClient(hab_http::Error),
    ReqwestError(reqwest::Error),
    IO(io::Error),
    Json(serde_json::Error),
    KeyReadError(PathBuf, io::Error),
    MissingHeader(String),
    InvalidHeader(String),
    NoFilePart,
    PackageReadError(PathBuf, io::Error),
    ParseIntError(num::ParseIntError),
    IdentNotFullyQualified,
    UploadFailed(String),
    UrlParseError(url::ParseError),
    WriteSyncFailed,
    NotSupported,
    TokioJoinError(JoinError),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let msg = match *self {
            Error::APIError(ref c, ref m) if !m.is_empty() => format!("[{}] {}", c, m),
            Error::APIError(ref c, _) => format!("[{}]", c),
            Error::BadResponseBody(ref e) => format!("Failed to read response body, {}", e),
            Error::DownloadWrite(ref p, ref e) => {
                format!("Failed to write contents of builder response, {}, {}",
                        p.display(),
                        e)
            }
            Error::HabitatCore(ref e) => format!("{}", e),
            Error::HabitatHttpClient(ref e) => format!("{}", e),
            Error::ReqwestError(ref err) => format!("{}", err),
            Error::IO(ref e) => format!("{}", e),
            Error::Json(ref e) => format!("{}", e),
            Error::KeyReadError(ref p, ref e) => {
                format!("Failed to read origin key, {}, {}", p.display(), e)
            }
            Error::MissingHeader(ref s) => format!("Response is missing a required header: {}", s),
            Error::InvalidHeader(ref s) => format!("Response header is invalid: {}", s),
            Error::NoFilePart => "An invalid path was passed - we needed a filename, and this \
                                  path does not have one"
                                                         .to_string(),
            Error::PackageReadError(ref p, ref e) => {
                format!("Failed to read package artifact, {}, {}", p.display(), e)
            }
            Error::ParseIntError(ref err) => format!("{}", err),
            Error::IdentNotFullyQualified => {
                "Cannot perform the specified operation. Specify a fully qualifed package \
                 identifier (ex: core/busybox-static/1.42.2/20170513215502)"
                                                                            .to_string()
            }
            Error::UploadFailed(ref s) => format!("Upload failed: {}", s),
            Error::UrlParseError(ref e) => format!("{}", e),
            Error::WriteSyncFailed => {
                "Could not write to destination; perhaps the disk is full?".to_string()
            }
            Error::NotSupported => "The specified operation is not supported.".to_string(),
            Error::TokioJoinError(ref e) => format!("{}", e),
        };
        write!(f, "{}", msg)
    }
}

impl error::Error for Error {}

impl From<hab_core::Error> for Error {
    fn from(err: hab_core::Error) -> Error { Error::HabitatCore(err) }
}

impl From<hab_http::Error> for Error {
    fn from(err: hab_http::Error) -> Error { Error::HabitatHttpClient(err) }
}

impl From<reqwest::Error> for Error {
    fn from(err: reqwest::Error) -> Error { Error::ReqwestError(err) }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error { Error::IO(err) }
}

impl From<serde_json::Error> for Error {
    fn from(err: serde_json::Error) -> Error { Error::Json(err) }
}

impl From<url::ParseError> for Error {
    fn from(err: url::ParseError) -> Error { Error::UrlParseError(err) }
}

impl From<JoinError> for Error {
    fn from(err: JoinError) -> Error { Error::TokioJoinError(err) }
}
<|endoftext|>