<commit_before>#![deny(warnings)]

extern crate comrak;
#[cfg(feature="csv")]
extern crate csv;
extern crate svgbob;
extern crate typed_arena;
extern crate url;
extern crate url_path;
#[macro_use]
extern crate log;
extern crate ammonia;
#[macro_use]
extern crate maplit;

use typed_arena::Arena;
use comrak::{format_html, parse_document, ComrakOptions};
use comrak::nodes::{AstNode, NodeHtmlBlock, NodeValue};
use std::collections::HashMap;
use errors::Error;
use svgbob::Grid;
use url_path::UrlPath;

mod errors {
    use std::string::FromUtf8Error;
    #[derive(Debug)]
    pub enum Error {
        ParseError,
        PluginError,
        Utf8Error(FromUtf8Error),
    }
    impl From<FromUtf8Error> for Error {
        fn from(e: FromUtf8Error) -> Self {
            Error::Utf8Error(e)
        }
    }
}

/// convert bob ascii diagrams to svg
fn bob_handler(s: &str, _settings: &Settings) -> Result<String, Error> {
    let grid = Grid::from_str(s, &svgbob::Settings::compact());
    let (width, height) = grid.get_size();
    let svg = grid.get_svg();
    let bob_container = format!(
        "
{}
",
        width, height, svg
    );
    Ok(bob_container)
}

/// convert csv content into html table
#[cfg(feature="csv")]
fn csv_handler(s: &str, settings: &Settings) -> Result<String>{
    let now = std::time::SystemTime::now();
    let mut buff = String::new();
    let mut rdr = csv::Reader::from_string(s);
    buff.push_str("
");
    buff.push_str("
");
    for header in rdr.byte_headers() {
        buff.push_str("
");
        for h in header {
            buff.push_str(&format!("{}	", String::from_utf8(h)?));
        }
        buff.push_str("
");
    }
    buff.push_str("
");
    buff.push_str("
");
    buff.push_str("
");
    for record in rdr.byte_records().filter_map(|r| r.ok()) {
        buff.push_str("
");
        for r in record {
            buff.push_str(&format!("{}	", String::from_utf8(r)?));
        }
        buff.push_str("
");
    }
    buff.push_str("
");
    buff.push_str("
");
    Ok(buff)
}

pub struct Settings {
    base_dir: Option<String>,
    clean_xss: bool,
}

impl Default for Settings {
    fn default() -> Self {
        Settings{base_dir: None, clean_xss: true}
    }
}

pub fn parse(arg: &str) -> Result<String, Error> {
    parse_with_settings(arg, &Settings::default())
}

pub fn parse_with_base_dir(arg: &str, base_dir: &str) -> Result<String, Error> {
    let settings = Settings {
            base_dir: Some(base_dir.to_string()),
            ..Default::default()
    };
    parse_with_settings(arg, &settings)
}

pub fn parse_with_settings(arg: &str, settings: &Settings) -> Result<String, Error> {
    let mut plugins: HashMap<String, Box<Fn(&str, &Settings) -> Result<String, Error>>> =
        HashMap::new();
    plugins.insert("bob".into(), Box::new(bob_handler));
    #[cfg(feature="csv")]
    plugins.insert("csv".into(), Box::new(csv_handler));
    let html = parse_via_comrak(arg, &plugins, settings);
    html
}

pub fn parse_bob(arg: &str) -> Result<String, Error> {
    bob_handler(arg, &Settings::default())
}

#[cfg(feature="csv")]
pub fn parse_csv(arg: &str) -> Result<String> {
    csv_handler(arg, &Settings::default())
}

/// Plugin info, format:
/// [<selector>] <plugin_name>[@version][://<URI>]
/// example:
/// #table1 csv://data_file.csv
#[allow(dead_code)]
struct PluginInfo {
    selector: Option<String>,
    plugin_name: String,
    version: Option<String>,
    uri: Option<String>,
}

fn parse_via_comrak(
    arg: &str,
    plugins: &HashMap<String, Box<Fn(&str, &Settings) -> Result<String, Error>>>,
    settings: &Settings,
) -> Result<String, Error> {
    // The returned nodes are created in the supplied Arena, and are bound by its lifetime.
    let arena = Arena::new();
    let option = ComrakOptions {
        hardbreaks: true,
        github_pre_lang: true,
        default_info_string: None,
        width: 0,
        ext_strikethrough: true,
        ext_tagfilter: true,
        ext_table: true,
        ext_autolink: true,
        ext_tasklist: true,
        ext_superscript: false,
        ext_header_ids: None,
        ext_footnotes: true,
        ext_description_lists: true,
        smart: false,
        safe: true,
    };

    let root = parse_document(&arena, arg, &option);

    fn iter_nodes<'a, F>(node: &'a AstNode<'a>, f: &F)
    where
        F: Fn(&'a AstNode<'a>),
    {
        f(node);
        for c in node.children() {
            iter_nodes(c, f);
        }
    }

    iter_nodes(root, &|node| {
        let ref mut value = node.data.borrow_mut().value;
        let new_value = match value {
            &mut NodeValue::CodeBlock(ref codeblock) => {
                let codeblock_info = String::from_utf8(codeblock.info.to_owned()).unwrap();
                if let Some(handler) =  plugins.get(&codeblock_info) {
                    let codeblock_literal =
                        String::from_utf8(codeblock.literal.to_owned()).unwrap();
                    match handler(&codeblock_literal, settings) {
                        Ok(out) => NodeValue::HtmlBlock(NodeHtmlBlock {
                            literal: out.into_bytes(),
                            block_type: 0,
                        }),
                        Err(_) => NodeValue::CodeBlock(codeblock.clone()),
                    }
                }else{
                    value.clone()
                }
            }
            &mut NodeValue::Link(ref nodelink) => {
                if let Ok(url) = String::from_utf8(nodelink.url.clone()){
                    if let Some(ref base_dir) = settings.base_dir {
                        let url1 = UrlPath::new(&url);
                        let url2 = url1.normalize();
                        let url3 = if url1.is_external(){
                            url2
                        }else if url1.is_absolute(){
                            url2
                        }else{
                            format!("{}/{}", base_dir, url)
                        };
                        let url4 = UrlPath::new(&url3);
                        let url5 = url4.normalize();
                        let url6 = format!("/#{}", url5);
                        info!("url6: {}", url6);
                        let mut new_nodelink = nodelink.clone();
                        new_nodelink.url = url6.into_bytes();
                        NodeValue::Link(new_nodelink)
                    }else{
                        value.clone()
                    }
                }else{
                    value.clone()
                }
            }
            _ => value.clone(),
        };
        *value = new_value;
    });

    let mut html = vec![];

    if let Ok(()) = format_html(root, &ComrakOptions::default(), &mut html) {
        let render_html = String::from_utf8(html)?;
        if settings.clean_xss{
            let map:HashMap<&str,Vec<&str>> = hashmap!{
                "svg" => vec!["class","font-family","font-size","height","width","xmlns"],
                "text" => vec!["class", "x","y"],
                "rect" => vec!["class", "fill", "height", "width", "x", "y", "stroke", "stroke-width"],
                "circle" => vec!["class","cx","cy","r", "fill", "stroke", "stroke-width"],
                "path" => vec!["class","fill"],
                "line" => vec!["class", "x1","x2", "y1", "y2", "marker-start", "marker-end"],
                "path" => vec!["class","d","fill","stroke","stroke-dasharry"],
                "polygon" => vec!["class","points","fill","stroke","stroke-dasharry"],
                "g" => vec![],
                "defs" => vec![],
                "style" => vec!["type"],
                "marker" => vec!["id","markerHeight","markerUnits","markerWidth","orient","refX", "refY", "viewBox"]
            };
            let mut builder = ammonia::Builder::default();
            for (k,v) in map.iter(){
                builder.add_tags(std::iter::once(*k));
                for att in v.iter(){
                    builder.add_tag_attributes(k, std::iter::once(*att));
                }
            }

            let clean_html = builder
                .clean(&render_html)
                .to_string();
            Ok(clean_html)
        }else{
            Ok(render_html)
        }
    } else {
        Err(Error::ParseError)
    }
}

<commit_msg>refactor ammonia builder in its own function<commit_after>#![deny(warnings)]

extern crate comrak;
#[cfg(feature="csv")]
extern crate csv;
extern crate svgbob;
extern crate typed_arena;
extern crate url;
extern crate url_path;
#[macro_use]
extern crate log;
extern crate ammonia;
#[macro_use]
extern crate maplit;

use typed_arena::Arena;
use comrak::{format_html, parse_document, ComrakOptions};
use comrak::nodes::{AstNode, NodeHtmlBlock, NodeValue};
use std::collections::HashMap;
use errors::Error;
use svgbob::Grid;
use ammonia::Builder;
use url_path::UrlPath;

mod errors {
    use std::string::FromUtf8Error;
    #[derive(Debug)]
    pub enum Error {
        ParseError,
        PluginError,
        Utf8Error(FromUtf8Error),
    }
    impl From<FromUtf8Error> for Error {
        fn from(e: FromUtf8Error) -> Self {
            Error::Utf8Error(e)
        }
    }
}

/// convert bob ascii diagrams to svg
fn bob_handler(s: &str, _settings: &Settings) -> Result<String, Error> {
    let grid = Grid::from_str(s, &svgbob::Settings::compact());
    let (width, height) = grid.get_size();
    let svg = grid.get_svg();
    let bob_container = format!(
        "
{}
",
        width, height, svg
    );
    Ok(bob_container)
}

/// convert csv content into html table
#[cfg(feature="csv")]
fn csv_handler(s: &str, settings: &Settings) -> Result<String>{
    let now = std::time::SystemTime::now();
    let mut buff = String::new();
    let mut rdr = csv::Reader::from_string(s);
    buff.push_str("
");
    buff.push_str("
");
    for header in rdr.byte_headers() {
        buff.push_str("
");
        for h in header {
            buff.push_str(&format!("{}	", String::from_utf8(h)?));
        }
        buff.push_str("
");
    }
    buff.push_str("
");
    buff.push_str("
");
    buff.push_str("
");
    for record in rdr.byte_records().filter_map(|r| r.ok()) {
        buff.push_str("
");
        for r in record {
            buff.push_str(&format!("{}	", String::from_utf8(r)?));
        }
        buff.push_str("
");
    }
    buff.push_str("
");
    buff.push_str("
");
    Ok(buff)
}

pub struct Settings {
    base_dir: Option<String>,
    clean_xss: bool,
}

impl Default for Settings {
    fn default() -> Self {
        Settings{base_dir: None, clean_xss: true}
    }
}

pub fn parse(arg: &str) -> Result<String, Error> {
    parse_with_settings(arg, &Settings::default())
}

pub fn parse_with_base_dir(arg: &str, base_dir: &str) -> Result<String, Error> {
    let settings = Settings {
            base_dir: Some(base_dir.to_string()),
            ..Default::default()
    };
    parse_with_settings(arg, &settings)
}

pub fn parse_with_settings(arg: &str, settings: &Settings) -> Result<String, Error> {
    let mut plugins: HashMap<String, Box<Fn(&str, &Settings) -> Result<String, Error>>> =
        HashMap::new();
    plugins.insert("bob".into(), Box::new(bob_handler));
    #[cfg(feature="csv")]
    plugins.insert("csv".into(), Box::new(csv_handler));
    let html = parse_via_comrak(arg, &plugins, settings);
    html
}

pub fn parse_bob(arg: &str) -> Result<String, Error> {
    bob_handler(arg, &Settings::default())
}

#[cfg(feature="csv")]
pub fn parse_csv(arg: &str) -> Result<String> {
    csv_handler(arg, &Settings::default())
}

/// Plugin info, format:
/// [<selector>] <plugin_name>[@version][://<URI>]
/// example:
/// #table1 csv://data_file.csv
#[allow(dead_code)]
struct PluginInfo {
    selector: Option<String>,
    plugin_name: String,
    version: Option<String>,
    uri: Option<String>,
}

fn parse_via_comrak(
    arg: &str,
    plugins: &HashMap<String, Box<Fn(&str, &Settings) -> Result<String, Error>>>,
    settings: &Settings,
) -> Result<String, Error> {
    // The returned nodes are created in the supplied Arena, and are bound by its lifetime.
    let arena = Arena::new();
    let option = ComrakOptions {
        hardbreaks: true,
        github_pre_lang: true,
        default_info_string: None,
        width: 0,
        ext_strikethrough: true,
        ext_tagfilter: true,
        ext_table: true,
        ext_autolink: true,
        ext_tasklist: true,
        ext_superscript: false,
        ext_header_ids: None,
        ext_footnotes: true,
        ext_description_lists: true,
        smart: false,
        safe: true,
    };

    let root = parse_document(&arena, arg, &option);

    fn iter_nodes<'a, F>(node: &'a AstNode<'a>, f: &F)
    where
        F: Fn(&'a AstNode<'a>),
    {
        f(node);
        for c in node.children() {
            iter_nodes(c, f);
        }
    }

    iter_nodes(root, &|node| {
        let ref mut value = node.data.borrow_mut().value;
        let new_value = match value {
            &mut NodeValue::CodeBlock(ref codeblock) => {
                let codeblock_info = String::from_utf8(codeblock.info.to_owned()).unwrap();
                if let Some(handler) =  plugins.get(&codeblock_info) {
                    let codeblock_literal =
                        String::from_utf8(codeblock.literal.to_owned()).unwrap();
                    match handler(&codeblock_literal, settings) {
                        Ok(out) => NodeValue::HtmlBlock(NodeHtmlBlock {
                            literal: out.into_bytes(),
                            block_type: 0,
                        }),
                        Err(_) => NodeValue::CodeBlock(codeblock.clone()),
                    }
                }else{
                    value.clone()
                }
            }
            &mut NodeValue::Link(ref nodelink) => {
                if let Ok(url) = String::from_utf8(nodelink.url.clone()){
                    if let Some(ref base_dir) = settings.base_dir {
                        let url1 = UrlPath::new(&url);
                        let url2 = url1.normalize();
                        let url3 = if url1.is_external(){
                            url2
                        }else if url1.is_absolute(){
                            url2
                        }else{
                            format!("{}/{}", base_dir, url)
                        };
                        let url4 = UrlPath::new(&url3);
                        let url5 = url4.normalize();
                        let url6 = format!("/#{}", url5);
                        info!("url6: {}", url6);
                        let mut new_nodelink = nodelink.clone();
                        new_nodelink.url = url6.into_bytes();
                        NodeValue::Link(new_nodelink)
                    }else{
                        value.clone()
                    }
                }else{
                    value.clone()
                }
            }
            _ => value.clone(),
        };
        *value = new_value;
    });

    let mut html = vec![];

    if let Ok(()) = format_html(root, &ComrakOptions::default(), &mut html) {
        let render_html = String::from_utf8(html)?;
        if settings.clean_xss{
            let builder = ammonia_builder();
            let clean_html = builder
                .clean(&render_html)
                .to_string();
            Ok(clean_html)
        }else{
            Ok(render_html)
        }
    } else {
        Err(Error::ParseError)
    }
}

/// Create an ammonia builder and whitelisting the svg tags and attributes
fn ammonia_builder<'a>() -> Builder<'a> {
    let map:HashMap<&str,Vec<&str>> = hashmap!{
        "svg" => vec!["class","font-family","font-size","height","width","xmlns"],
        "text" => vec!["class", "x","y"],
        "rect" => vec!["class", "fill", "height", "width", "x", "y", "stroke", "stroke-width"],
        "circle" => vec!["class","cx","cy","r", "fill", "stroke", "stroke-width"],
        "path" => vec!["class","fill"],
        "line" => vec!["class", "x1","x2", "y1", "y2", "marker-start", "marker-end"],
        "path" => vec!["class","d","fill","stroke","stroke-dasharry"],
        "polygon" => vec!["class","points","fill","stroke","stroke-dasharry"],
        "g" => vec![],
        "defs" => vec![],
        "style" => vec!["type"],
        "marker" => vec!["id","markerHeight","markerUnits","markerWidth","orient","refX", "refY", "viewBox"]
    };
    let mut builder = Builder::default();
    for (k,v) in map.iter(){
        builder.add_tags(std::iter::once(*k));
        for att in v.iter(){
            builder.add_tag_attributes(k, std::iter::once(*att));
        }
    }
    builder
}

<|endoftext|>


<commit_before>extern crate time;
extern crate byteorder;

mod constants;

use std::option::Option;
use std::cmp::Ordering;
use std::io::Write;
use std::net::TcpStream;

use byteorder::{BigEndian, WriteBytesExt};

#[test]
fn constructor() {
    let c = Connection::new("localhost", 4730);

    assert!(c.host == "localhost");
    assert!(c.port == 4730);
    assert!(c.state == ConnectionState::INIT);

    let now = time::now_utc();
    match c.state_time {
        Some(c_time) => {
            let result = now.cmp(&c_time);  // Could fail if no nanoseconds
            assert_eq!(Ordering::Greater, result);
        },
        None => assert!(false)
    }
}

#[test]
fn change_state() {
    let mut c = Connection::new("localhost", 4730);

    c.change_state(ConnectionState::INIT);
    assert!(c.state == ConnectionState::INIT);
}

#[test]
fn packet_constructor() {
    let data = [0x00u8];
    let p = Packet::new(0x00000000, 0x00000000, &data);
    assert!(p.code == 0x00000000);
    assert!(p.ptype == 0x00000000);
    assert!(p.data.len() == 1);
    match p.conn {
        None => {},
        Some(_) => panic!("Should not have a connection assigned.")
    }
}

#[test]
#[should_panic]
fn send_packet() {
    let mut conn = Connection::new("localost", 4730);
    let data = [0x00u8];
    let p = Packet::new(0x00000000, 0x00000000, &data);
    conn.sendPacket(&p)
}

#[derive(PartialEq)]
enum ConnectionState {
    INIT,
}

struct Connection {
    host: String,
    port: u16,
    conn: Option<TcpStream>,
    connected: bool,
    connect_time: Option<time::Tm>,
    state: ConnectionState,
    state_time: Option<time::Tm>,
}

struct Packet<'a> {
    code: u32,
    ptype: u32,
    data: &'a [u8],
    conn: Option<&'a Connection>,
}

impl Connection {
    fn new(host: &str, port: u16) -> Connection {
        let mut c = Connection {
            host: host.to_string(),
            port: port,
            conn: None,
            connected: false,
            connect_time: None,
            state: ConnectionState::INIT,
            state_time: None,
        };
        c.change_state(ConnectionState::INIT);
        return c
    }

    fn change_state(&mut self, state: ConnectionState) {
        self.state_time = Some(time::now_utc());
        self.state = state;
    }

    fn connect(&mut self) {
        match self.conn {
            None => {
                self.conn = Some(TcpStream::connect((&*self.host, self.port)).unwrap());
                self.connected = true;
                self.connect_time = Some(time::now_utc());
            },
            Some(_) => { /* log debug "already connected" */ },
        }
    }

    fn disconnect(&mut self) {
        match self.conn {
            Some(_) => self.conn = None,
            None => { /* log debug "already disconnected" */ },
        }
    }

    fn reconnect(&mut self) {
        self.disconnect();
        self.connect()
    }

    fn sendPacket(&mut self, packet: &Packet) {
        match self.conn {
            Some(ref mut c) => {
                c.write_u32::<BigEndian>(packet.code).unwrap();
                c.write_u32::<BigEndian>(packet.ptype);
                c.write_u32::<BigEndian>(packet.data.len() as u32).unwrap();
                c.write_all(packet.data).unwrap()
            },
            None => panic!("Attempted to send packet on disconnected socket")
        }
    }
}

impl<'a> PartialEq for Packet<'a> {
    fn eq(&self, other: &Packet) -> bool {
        self.code == other.code &&
        self.ptype == other.ptype &&
        self.data == other.data
    }
}

impl<'a> Packet<'a> {
    fn new(code: u32, ptype: u32, data: &'a [u8]) -> Packet {
        Packet {
            code: code,
            ptype: ptype,
            data: data,
            conn: None,
        }
    }
}
<commit_msg>Adding readpacket support<commit_after>extern crate time;
extern crate byteorder;

mod constants;

use std::option::Option;
use std::cmp::Ordering;
use std::io::Write;
use std::io::Read;
use std::net::TcpStream;

use byteorder::{BigEndian, WriteBytesExt};
use byteorder::ReadBytesExt;

#[test]
fn constructor() {
    let c = Connection::new("localhost", 4730);

    assert!(c.host == "localhost");
    assert!(c.port == 4730);
    assert!(c.state == ConnectionState::INIT);

    let now = time::now_utc();
    match c.state_time {
        Some(c_time) => {
            let result = now.cmp(&c_time);  // Could fail if no nanoseconds
            assert_eq!(Ordering::Greater, result);
        },
        None => assert!(false)
    }
}

#[test]
fn change_state() {
    let mut c = Connection::new("localhost", 4730);

    c.change_state(ConnectionState::INIT);
    assert!(c.state == ConnectionState::INIT);
}

#[test]
fn packet_constructor() {
    let data: Box<[u8]> = Box::new([0x00u8]);
    let p = Packet::new(0x00000000, 0x00000000, data);
    assert!(p.code == 0x00000000);
    assert!(p.ptype == 0x00000000);
    assert!(p.data.len() == 1);
}

#[test]
#[should_panic]
fn send_packet() {
    let mut conn = Connection::new("localost", 4730);
    let data: Box<[u8]> = Box::new([0x00u8]);
    let p = Packet::new(0x00000000, 0x00000000, data);
    conn.sendPacket(&p)
}

#[derive(PartialEq)]
enum ConnectionState {
    INIT,
}

struct Connection {
    host: String,
    port: u16,
    conn: Option<TcpStream>,
    connected: bool,
    connect_time: Option<time::Tm>,
    state: ConnectionState,
    state_time: Option<time::Tm>,
}

struct Packet {
    code: u32,
    ptype: u32,
    data: Box<[u8]>,
}

impl Connection {
    fn new(host: &str, port: u16) -> Connection {
        let mut c = Connection {
            host: host.to_string(),
            port: port,
            conn: None,
            connected: false,
            connect_time: None,
            state: ConnectionState::INIT,
            state_time: None,
        };
        c.change_state(ConnectionState::INIT);
        return c
    }

    fn change_state(&mut self, state: ConnectionState) {
        self.state_time = Some(time::now_utc());
        self.state = state;
    }

    fn connect(&mut self) {
        match self.conn {
            None => {
                self.conn = Some(TcpStream::connect((&*self.host, self.port)).unwrap());
self.connected = true;
                self.connect_time = Some(time::now_utc());
            },
            Some(_) => { /* log debug "already connected" */ },
        }
    }

    fn disconnect(&mut self) {
        match self.conn {
            Some(_) => self.conn = None,
            None => { /* log debug "already disconnected" */ },
        }
    }

    fn reconnect(&mut self) {
        self.disconnect();
        self.connect()
    }

    fn sendPacket(&mut self, packet: &Packet) {
        match self.conn {
            Some(ref mut c) => {
                c.write_u32::<BigEndian>(packet.code).unwrap();
                c.write_u32::<BigEndian>(packet.ptype);
                c.write_u32::<BigEndian>(packet.data.len() as u32).unwrap();
                c.write_all(&packet.data).unwrap()
            },
            None => panic!("Attempted to send packet on disconnected socket")
        }
    }

    fn readPacket(&mut self) -> Packet {
        match self.conn {
            Some(ref mut c) => {
                let code    = c.read_u32::<BigEndian>().unwrap();
                let ptype   = c.read_u32::<BigEndian>().unwrap();
                let datalen = c.read_u32::<BigEndian>().unwrap();
                let mut datastream = c.take(datalen as u64);
                let mut buf: Vec<u8> = Vec::new();
                datastream.read_to_end(&mut buf).unwrap();
                return Packet {
                    code: code,
                    ptype: ptype,
                    data: buf.into_boxed_slice(),
                }
            },
            None => panic!("Attempted to read packet on disconnected socket")
        }
    }
}

impl PartialEq for Packet {
    fn eq(&self, other: &Packet) -> bool {
        self.code == other.code &&
        self.ptype == other.ptype &&
        self.data == other.data
    }
}

impl Packet {
    fn new(code: u32, ptype: u32, data: Box<[u8]>) -> Packet {
        Packet {
            code: code,
            ptype: ptype,
            data: data,
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_name = "azure"]
#![crate_type = "rlib"]
#![cfg_attr(feature = "plugins", feature(custom_derive, plugin, rustc_attrs, rustc_macro))]
#![cfg_attr(feature = "plugins", plugin(heapsize_plugin))]

extern crate libc;
#[cfg(feature = "plugins")]
extern crate serde;
#[cfg(feature = "plugins")]
#[macro_use]
extern crate serde_derive;
extern crate euclid;
extern crate skia;
#[macro_use]
#[cfg(feature = "plugins")]
extern crate heapsize;
#[cfg(target_os = "linux")]
extern crate x11;
#[cfg(target_os = "android")]
extern crate egl;
#[cfg(not(target_os = "macos"))]
extern crate freetype;
#[cfg(target_os = "macos")]
extern crate core_foundation;
#[cfg(target_os = "macos")]
extern crate core_graphics;
#[cfg(target_os = "macos")]
extern crate core_text;

pub use azure::{AzFontOptions, AzFloat, enum_AzSurfaceType, AZ_SURFACE_DATA,
                AZ_SURFACE_D2D1_BITMAP, AZ_SURFACE_D2D1_DRAWTARGET, AZ_SURFACE_CAIRO, AZ_SURFACE_CAIRO_IMAGE,
                AZ_SURFACE_COREGRAPHICS_IMAGE, AZ_SURFACE_COREGRAPHICS_CGCONTEXT, AZ_SURFACE_SKIA, AZ_SURFACE_DUAL_DT,
                enum_AzSurfaceFormat, AZ_FORMAT_B8G8R8A8, AZ_FORMAT_B8G8R8X8, AZ_FORMAT_R5G6B5,
                AZ_FORMAT_A8, AzSurfaceFormat, enum_AzBackendType, AZ_BACKEND_NONE,
                AZ_BACKEND_DIRECT2D, AZ_BACKEND_COREGRAPHICS, AZ_BACKEND_COREGRAPHICS_ACCELERATED, AZ_BACKEND_CAIRO,
                AZ_BACKEND_SKIA, AZ_BACKEND_RECORDING, AzBackendType, enum_AzFontType,
                AZ_FONT_DWRITE, AZ_FONT_GDI, AZ_FONT_MAC, AZ_FONT_SKIA,
                AZ_FONT_CAIRO, AZ_FONT_COREGRAPHICS, enum_AzNativeSurfaceType, AZ_NATIVE_SURFACE_D3D10_TEXTURE,
                AZ_NATIVE_SURFACE_CAIRO_SURFACE, AZ_NATIVE_SURFACE_CGCONTEXT, enum_AzNativeFontType, AZ_NATIVE_FONT_DWRITE_FONT_FACE,
                AZ_NATIVE_FONT_GDI_FONT_FACE, AZ_NATIVE_FONT_MAC_FONT_FACE, AZ_NATIVE_FONT_SKIA_FONT_FACE, AZ_NATIVE_FONT_CAIRO_FONT_FACE,
                enum_AzFontStyle, AZ_FONT_STYLE_NORMAL, AZ_FONT_STYLE_ITALIC, AZ_FONT_STYLE_BOLD,
                AZ_FONT_STYLE_BOLD_ITALIC, enum_AzCompositionOp, AZ_OP_OVER, AZ_OP_ADD,
                AZ_OP_ATOP, AZ_OP_OUT, AZ_OP_IN, AZ_OP_SOURCE,
                AZ_OP_DEST_IN, AZ_OP_DEST_OUT, AZ_OP_DEST_OVER, AZ_OP_DEST_ATOP,
                AZ_OP_XOR, AZ_OP_MULTIPLY, AZ_OP_SCREEN, AZ_OP_OVERLAY,
                AZ_OP_DARKEN, AZ_OP_LIGHTEN, AZ_OP_COLOR_DODGE, AZ_OP_COLOR_BURN,
                AZ_OP_HARD_LIGHT, AZ_OP_SOFT_LIGHT, AZ_OP_DIFFERENCE, AZ_OP_EXCLUSION,
                AZ_OP_HUE, AZ_OP_SATURATION, AZ_OP_COLOR, AZ_OP_LUMINOSITY,
                AZ_OP_COUNT, enum_AzExtendMode, AZ_EXTEND_CLAMP, AZ_EXTEND_REPEAT,
                AZ_EXTEND_REFLECT, enum_AzFillRule, AZ_FILL_WINDING, AZ_FILL_EVEN_ODD,
                enum_AzAntialiasMode, AZ_AA_NONE, AZ_AA_GRAY, AZ_AA_SUBPIXEL,
                enum_AzFilter, AZ_FILTER_LINEAR, AZ_FILTER_POINT, AzFilter, enum_AzPatternType,
                AZ_PATTERN_COLOR, AZ_PATTERN_SURFACE, AZ_PATTERN_LINEAR_GRADIENT, AZ_PATTERN_RADIAL_GRADIENT,
                enum_AzJoinStyle, AZ_JOIN_BEVEL, AZ_JOIN_ROUND, AZ_JOIN_MITER,
                AZ_JOIN_MITER_OR_BEVEL, enum_AzCapStyle, AZ_CAP_BUTT, AZ_CAP_ROUND,
                AZ_CAP_SQUARE, enum_AzSamplingBounds, AZ_SAMPLING_UNBOUNDED, AZ_SAMPLING_BOUNDED,
                enum_AzSide, AZ_eSideTop, AZ_eSideRight, AZ_eSideBottom,
                AZ_eSideLeft, struct__AzColor, AzColor, struct__AzGradientStop,
                AzGradientStop, struct__AzIntRect, AzIntRect, struct__AzRect,
                AzRect, struct__AzIntPoint, AzIntPoint, struct__AzPoint,
                AzPoint, struct__AzIntSize, AzIntSize, struct__AzSize,
                AzSize, struct__AzMatrix, AzMatrix, struct__AzDrawOptions,
                AzDrawOptions, struct__AzStrokeOptions, AzStrokeOptions, struct__AzDrawSurfaceOptions,
                AzDrawSurfaceOptions, struct__AzGlyph, AzGlyph, struct__AzGlyphBuffer,
                AzGlyphBuffer, struct__AzNativeFont, AzNativeFont, AzGradientStopsRef,
                AzDrawTargetRef, AzPatternRef, AzColorPatternRef, AzScaledFontRef,
                AzGlyphRenderingOptionsRef, AzSourceSurfaceRef, AzDataSourceSurfaceRef, AzDrawSurfaceOptionsRef,
                AzGLContext, AzGLContextMetadataRef,
                AzPathRef, AzPathBuilderRef, AzSanityCheck, AzCreateColorPattern,
                AzCreateDrawTarget, AzCreateDrawTargetForData, AzCreateDrawTargetSkiaWithGrContextAndFBO,
                AzRetainDrawTarget, AzReleaseDrawTarget, AzDrawTargetGetSize, AzDrawTargetFlush,
                AzDrawTargetClearRect, AzDrawTargetCopySurface, AzDrawTargetFillRect, AzDrawTargetStrokeRect, AzDrawTargetStrokeLine,
                AzDrawTargetFill, AzDrawTargetStroke, AzDrawTargetPushClip, AzDrawTargetPopClip, AzDrawTargetFillGlyphs,
                AzDrawTargetDrawSurface, AzDrawTargetGetSnapshot, AzDrawTargetCreateSourceSurfaceFromData, AzReleaseSourceSurface,
                AzSourceSurfaceGetSize, AzSourceSurfaceGetFormat, AzSourceSurfaceGetDataSurface, AzDataSourceSurfaceGetData,
                AzDataSourceSurfaceGetStride, AzCreateScaledFontForNativeFont, AzReleaseScaledFont, AzDrawTargetSetTransform,
                AzCreateFontOptionsForName, AzDestroyFontOptions, AzCreatePathBuilder, AzPathCopyToBuilder, AzPathContainsPoint,
                AzReleasePathBuilder, AzPathBuilderMoveTo, AzPathBuilderLineTo, AzPathBuilderFinish, AzReleasePath};

pub mod azure_hl;
pub mod scaled_font;

#[cfg(target_os = "linux")]
pub mod test;

pub mod linkhack;

pub mod azure;
<commit_msg>Switch rustc_macro to proc_macro<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_name = "azure"]
#![crate_type = "rlib"]
#![cfg_attr(feature = "plugins", feature(custom_derive, plugin, proc_macro, rustc_attrs))]
#![cfg_attr(feature = "plugins", plugin(heapsize_plugin))]

extern crate libc;
#[cfg(feature = "plugins")]
extern crate serde;
#[cfg(feature = "plugins")]
#[macro_use]
extern crate serde_derive;
extern crate euclid;
extern crate skia;
#[macro_use]
#[cfg(feature = "plugins")]
extern crate heapsize;
#[cfg(target_os = "linux")]
extern crate x11;
#[cfg(target_os = "android")]
extern crate egl;
#[cfg(not(target_os = "macos"))]
extern crate freetype;
#[cfg(target_os = "macos")]
extern crate core_foundation;
#[cfg(target_os = "macos")]
extern crate core_graphics;
#[cfg(target_os = "macos")]
extern crate core_text;

pub use azure::{AzFontOptions, AzFloat, enum_AzSurfaceType, AZ_SURFACE_DATA,
                AZ_SURFACE_D2D1_BITMAP, AZ_SURFACE_D2D1_DRAWTARGET, AZ_SURFACE_CAIRO, AZ_SURFACE_CAIRO_IMAGE,
                AZ_SURFACE_COREGRAPHICS_IMAGE, AZ_SURFACE_COREGRAPHICS_CGCONTEXT, AZ_SURFACE_SKIA, AZ_SURFACE_DUAL_DT,
                enum_AzSurfaceFormat, AZ_FORMAT_B8G8R8A8, AZ_FORMAT_B8G8R8X8, AZ_FORMAT_R5G6B5,
                AZ_FORMAT_A8, AzSurfaceFormat, enum_AzBackendType, AZ_BACKEND_NONE,
                AZ_BACKEND_DIRECT2D, AZ_BACKEND_COREGRAPHICS, AZ_BACKEND_COREGRAPHICS_ACCELERATED, AZ_BACKEND_CAIRO,
                AZ_BACKEND_SKIA, AZ_BACKEND_RECORDING, AzBackendType, enum_AzFontType,
                AZ_FONT_DWRITE, AZ_FONT_GDI, AZ_FONT_MAC, AZ_FONT_SKIA,
                AZ_FONT_CAIRO, AZ_FONT_COREGRAPHICS, enum_AzNativeSurfaceType, AZ_NATIVE_SURFACE_D3D10_TEXTURE,
                AZ_NATIVE_SURFACE_CAIRO_SURFACE, AZ_NATIVE_SURFACE_CGCONTEXT, enum_AzNativeFontType, AZ_NATIVE_FONT_DWRITE_FONT_FACE,
                AZ_NATIVE_FONT_GDI_FONT_FACE, AZ_NATIVE_FONT_MAC_FONT_FACE, AZ_NATIVE_FONT_SKIA_FONT_FACE, AZ_NATIVE_FONT_CAIRO_FONT_FACE,
                enum_AzFontStyle, AZ_FONT_STYLE_NORMAL, AZ_FONT_STYLE_ITALIC, AZ_FONT_STYLE_BOLD,
                AZ_FONT_STYLE_BOLD_ITALIC, enum_AzCompositionOp, AZ_OP_OVER, AZ_OP_ADD,
                AZ_OP_ATOP, AZ_OP_OUT, AZ_OP_IN, AZ_OP_SOURCE,
                AZ_OP_DEST_IN, AZ_OP_DEST_OUT, AZ_OP_DEST_OVER, AZ_OP_DEST_ATOP,
                AZ_OP_XOR, AZ_OP_MULTIPLY, AZ_OP_SCREEN, AZ_OP_OVERLAY,
                AZ_OP_DARKEN, AZ_OP_LIGHTEN, AZ_OP_COLOR_DODGE, AZ_OP_COLOR_BURN,
                AZ_OP_HARD_LIGHT, AZ_OP_SOFT_LIGHT, AZ_OP_DIFFERENCE, AZ_OP_EXCLUSION,
                AZ_OP_HUE, AZ_OP_SATURATION, AZ_OP_COLOR, AZ_OP_LUMINOSITY,
                AZ_OP_COUNT, enum_AzExtendMode, AZ_EXTEND_CLAMP, AZ_EXTEND_REPEAT,
                AZ_EXTEND_REFLECT, enum_AzFillRule, AZ_FILL_WINDING, AZ_FILL_EVEN_ODD,
                enum_AzAntialiasMode, AZ_AA_NONE, AZ_AA_GRAY, AZ_AA_SUBPIXEL,
                enum_AzFilter, AZ_FILTER_LINEAR, AZ_FILTER_POINT, AzFilter, enum_AzPatternType,
                AZ_PATTERN_COLOR, AZ_PATTERN_SURFACE, AZ_PATTERN_LINEAR_GRADIENT, AZ_PATTERN_RADIAL_GRADIENT,
                enum_AzJoinStyle, AZ_JOIN_BEVEL, AZ_JOIN_ROUND, AZ_JOIN_MITER,
                AZ_JOIN_MITER_OR_BEVEL, enum_AzCapStyle, AZ_CAP_BUTT, AZ_CAP_ROUND,
                AZ_CAP_SQUARE, enum_AzSamplingBounds, AZ_SAMPLING_UNBOUNDED, AZ_SAMPLING_BOUNDED,
                enum_AzSide, AZ_eSideTop, AZ_eSideRight, AZ_eSideBottom,
                AZ_eSideLeft, struct__AzColor, AzColor, struct__AzGradientStop,
                AzGradientStop, struct__AzIntRect, AzIntRect, struct__AzRect,
                AzRect, struct__AzIntPoint, AzIntPoint, struct__AzPoint,
                AzPoint, struct__AzIntSize, AzIntSize, struct__AzSize,
                AzSize, struct__AzMatrix, AzMatrix, struct__AzDrawOptions,
                AzDrawOptions, struct__AzStrokeOptions, AzStrokeOptions, struct__AzDrawSurfaceOptions,
                AzDrawSurfaceOptions, struct__AzGlyph, AzGlyph, struct__AzGlyphBuffer,
                AzGlyphBuffer, struct__AzNativeFont, AzNativeFont, AzGradientStopsRef,
                AzDrawTargetRef, AzPatternRef, AzColorPatternRef, AzScaledFontRef,
                AzGlyphRenderingOptionsRef, AzSourceSurfaceRef, AzDataSourceSurfaceRef, AzDrawSurfaceOptionsRef,
                AzGLContext, AzGLContextMetadataRef,
                AzPathRef, AzPathBuilderRef, AzSanityCheck, AzCreateColorPattern,
                AzCreateDrawTarget, AzCreateDrawTargetForData, AzCreateDrawTargetSkiaWithGrContextAndFBO,
                AzRetainDrawTarget, AzReleaseDrawTarget, AzDrawTargetGetSize, AzDrawTargetFlush,
                AzDrawTargetClearRect, AzDrawTargetCopySurface, AzDrawTargetFillRect, AzDrawTargetStrokeRect, AzDrawTargetStrokeLine,
                AzDrawTargetFill, AzDrawTargetStroke, AzDrawTargetPushClip, AzDrawTargetPopClip, AzDrawTargetFillGlyphs,
                AzDrawTargetDrawSurface, AzDrawTargetGetSnapshot, AzDrawTargetCreateSourceSurfaceFromData, AzReleaseSourceSurface,
                AzSourceSurfaceGetSize, AzSourceSurfaceGetFormat, AzSourceSurfaceGetDataSurface, AzDataSourceSurfaceGetData,
                AzDataSourceSurfaceGetStride, AzCreateScaledFontForNativeFont, AzReleaseScaledFont, AzDrawTargetSetTransform,
                AzCreateFontOptionsForName, AzDestroyFontOptions, AzCreatePathBuilder, AzPathCopyToBuilder, AzPathContainsPoint,
                AzReleasePathBuilder, AzPathBuilderMoveTo, AzPathBuilderLineTo, AzPathBuilderFinish, AzReleasePath};

pub mod azure_hl;
pub mod scaled_font;

#[cfg(target_os = "linux")]
pub mod test;

pub mod linkhack;

pub mod azure;
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

extern crate ansi_term;
extern crate base64;
#[cfg(target_os = "linux")]
extern crate caps;
extern crate crypto as rust_crypto;
#[cfg(windows)]
extern crate ctrlc;

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;

#[cfg(not(windows))]
extern crate users as linux_users;

#[cfg(windows)]
extern crate habitat_win_users;
#[cfg(windows)]
extern crate widestring;
#[cfg(windows)]
extern crate winapi;
#[cfg(windows)]
extern crate windows_acl;

pub use self::error::{Error, Result};

pub mod binlink;
pub mod channel;
pub mod config;
pub mod crypto;
pub mod env;
pub mod error;
pub mod event;
pub mod fs;
pub mod os;
pub mod output;
pub mod package;
pub mod service;
pub mod url;
pub mod util;

use std::env::VarError;
use std::ffi::OsStr;
use std::fmt;
use std::path::PathBuf;

pub use crate::os::filesystem;
pub use crate::os::users;

pub const AUTH_TOKEN_ENVVAR: &str = "HAB_AUTH_TOKEN";

lazy_static::lazy_static! {
    pub static ref PROGRAM_NAME: String = {
        let arg0 = std::env::args().next().map(PathBuf::from);
        arg0.as_ref()
            .and_then(|p| p.file_stem())
            .and_then(|p| p.to_str())
            .unwrap()
            .to_string()
    };
}

/// A Builder channel
#[derive(Clone, Debug, PartialEq)]
pub struct ChannelIdent(String);

impl ChannelIdent {
    const LEGACY_ENVVAR: &'static str = "HAB_DEPOT_CHANNEL";
    pub const BLDR_ENVVAR: &'static str = "HAB_BLDR_CHANNEL";
    const UNSTABLE: &'static str = "unstable";
    const STABLE: &'static str = "stable";

    pub fn from_env_var(key: impl AsRef<OsStr>) -> std::result::Result<Self, VarError> {
        crate::env::var(key).map(ChannelIdent)
    }

    pub fn as_str(&self) -> &str {
        self.0.as_str()
    }

    pub fn stable() -> Self {
        Self::from(Self::STABLE)
    }

    pub fn unstable() -> Self {
        Self::from(Self::UNSTABLE)
    }

    fn legacy_default() -> Self {
        ChannelIdent(
            env::var(Self::LEGACY_ENVVAR)
                .ok()
                .and_then(|c| Some(c.to_string()))
                .unwrap_or(Self::STABLE.to_string()),
        )
    }
}

impl From<&str> for ChannelIdent {
    fn from(s: &str) -> Self {
        ChannelIdent(s.to_string())
    }
}

impl From<String> for ChannelIdent {
    fn from(s: String) -> Self {
        ChannelIdent(s)
    }
}

impl fmt::Display for ChannelIdent {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Default for ChannelIdent {
    fn default() -> Self {
        match env::var(ChannelIdent::BLDR_ENVVAR) {
            Ok(value) => ChannelIdent(value.to_string()),
            Err(_) => ChannelIdent::legacy_default(),
        }
    }
}
<commit_msg>Fix clippy lint: replace unwrap_or with unwrap_or_else<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

extern crate ansi_term;
extern crate base64;
#[cfg(target_os = "linux")]
extern crate caps;
extern crate crypto as rust_crypto;
#[cfg(windows)]
extern crate ctrlc;

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;

#[cfg(not(windows))]
extern crate users as linux_users;

#[cfg(windows)]
extern crate habitat_win_users;
#[cfg(windows)]
extern crate widestring;
#[cfg(windows)]
extern crate winapi;
#[cfg(windows)]
extern crate windows_acl;

pub use self::error::{Error, Result};

pub mod binlink;
pub mod channel;
pub mod config;
pub mod crypto;
pub mod env;
pub mod error;
pub mod event;
pub mod fs;
pub mod os;
pub mod output;
pub mod package;
pub mod service;
pub mod url;
pub mod util;

use std::env::VarError;
use std::ffi::OsStr;
use std::fmt;
use std::path::PathBuf;

pub use crate::os::filesystem;
pub use crate::os::users;

pub const AUTH_TOKEN_ENVVAR: &str = "HAB_AUTH_TOKEN";

lazy_static::lazy_static! {
    pub static ref PROGRAM_NAME: String = {
        let arg0 = std::env::args().next().map(PathBuf::from);
        arg0.as_ref()
            .and_then(|p| p.file_stem())
            .and_then(|p| p.to_str())
            .unwrap()
            .to_string()
    };
}

/// A Builder channel
#[derive(Clone, Debug, PartialEq)]
pub struct ChannelIdent(String);

impl ChannelIdent {
    const LEGACY_ENVVAR: &'static str = "HAB_DEPOT_CHANNEL";
    pub const BLDR_ENVVAR: &'static str = "HAB_BLDR_CHANNEL";
    const UNSTABLE: &'static str = "unstable";
    const STABLE: &'static str = "stable";

    pub fn from_env_var(key: impl AsRef<OsStr>) -> std::result::Result<Self, VarError> {
        crate::env::var(key).map(ChannelIdent)
    }

    pub fn as_str(&self) -> &str {
        self.0.as_str()
    }

    pub fn stable() -> Self {
        Self::from(Self::STABLE)
    }

    pub fn unstable() -> Self {
        Self::from(Self::UNSTABLE)
    }

    fn legacy_default() -> Self {
        ChannelIdent(
            env::var(Self::LEGACY_ENVVAR)
                .ok()
                .and_then(|c| Some(c.to_string()))
                .unwrap_or_else(|| Self::STABLE.to_string()),
        )
    }
}

impl From<&str> for ChannelIdent {
    fn from(s: &str) -> Self {
        ChannelIdent(s.to_string())
    }
}

impl From<String> for ChannelIdent {
    fn from(s: String) -> Self {
        ChannelIdent(s)
    }
}

impl fmt::Display for ChannelIdent {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Default for ChannelIdent {
    fn default() -> Self {
        match env::var(ChannelIdent::BLDR_ENVVAR) {
            Ok(value) => ChannelIdent(value.to_string()),
            Err(_) => ChannelIdent::legacy_default(),
        }
    }
}
<|endoftext|>


<commit_before>#![no_std]
//!
//! You can populate [`Petnames`] with your own word lists, but the word lists
//! from upstream [petname](https://github.com/dustinkirkland/petname) are
//! included with the `default_dictionary` feature (enabled by default). See
//! [`Petnames::small`], [`Petnames::medium`], and [`Petnames::large`] to select
//! a particular built-in word list, or use the [`Default`] implementation.
//!
//! The other thing you need is a random number generator from [rand][]:
//!
//! ```rust
//! let mut rng = rand::thread_rng();
//! let pname = petname::Petnames::default().generate(&mut rng, 7, ":");
//! ```
//!
//! It may be more convenient to use the default random number generator:
//!
//! ```rust
//! let pname = petname::Petnames::default().generate_one(7, ":");
//! ```
//!
//! There's a [convenience function][petname] that'll do all of this:
//!
//! ```rust
//! let pname = petname::petname(7, ":");
//! ```
//!
//! But the most flexible approach is to create an [`Iterator`] with
//! [`iter`][`Petnames::iter`]:
//!
//! ```rust
//! let mut rng = rand::thread_rng();
//! let petnames = petname::Petnames::default();
//! let ten_thousand_names: Vec<String> =
//!   petnames.iter(&mut rng, 3, "_").take(10000).collect();
//! ```
//!
//! You can modify the word lists to, for example, only use words beginning with
//! the letter "b":
//!
//! ```rust
//! let mut petnames = petname::Petnames::default();
//! petnames.retain(|s| s.starts_with("b"));
//! petnames.generate_one(3, ".");
//! ```
//!

extern crate alloc;

use alloc::{
    string::{String, ToString},
    vec::Vec,
};

use itertools::Itertools;
use rand::seq::SliceRandom;

/// Convenience function to generate a new petname from default word lists.
#[allow(dead_code)]
#[cfg(feature = "std_rng")]
#[cfg(feature = "default_dictionary")]
pub fn petname(words: u8, separator: &str) -> String {
    Petnames::new().generate_one(words, separator)
}

/// A word list.
pub type Words<'a> = Vec<&'a str>;

/// Word lists and the logic to combine them into _petnames_.
///
/// A _petname_ with `n` words will contain, in order:
///
///   * `n - 2` adverbs when `n >= 2`, otherwise 0 adverbs.
///   * 1 adjective when `n >= 2`, otherwise 0 adjectives.
///   * 1 name / noun when `n >= 1`, otherwise 0 names.
///
#[derive(Clone, Debug, PartialEq)]
pub struct Petnames<'a> {
    pub adjectives: Words<'a>,
    pub adverbs: Words<'a>,
    pub names: Words<'a>,
}

impl<'a> Petnames<'a> {
    /// Constructs a new `Petnames` from the default (small) word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn new() -> Self {
        Self::default()
    }

    /// Constructs a new `Petnames` from the small word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn small() -> Self {
        Self::init(
            include_str!("../words/small/adjectives.txt"),
            include_str!("../words/small/adverbs.txt"),
            include_str!("../words/small/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the medium word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn medium() -> Self {
        Self::init(
            include_str!("../words/medium/adjectives.txt"),
            include_str!("../words/medium/adverbs.txt"),
            include_str!("../words/medium/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the large word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn large() -> Self {
        Self::init(
            include_str!("../words/large/adjectives.txt"),
            include_str!("../words/large/adverbs.txt"),
            include_str!("../words/large/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the given word lists.
    ///
    /// The words are extracted from the given strings by splitting on whitespace.
    pub fn init(adjectives: &'a str, adverbs: &'a str, names: &'a str) -> Self {
        Self {
            adjectives: adjectives.split_whitespace().collect(),
            adverbs: adverbs.split_whitespace().collect(),
            names: names.split_whitespace().collect(),
        }
    }

    /// Keep words matching a predicate.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[cfg(feature = "default_dictionary")]
    /// let mut petnames = petname::Petnames::default();
    /// # #[cfg(feature = "default_dictionary")]
    /// petnames.retain(|s| s.starts_with("b"));
    /// # #[cfg(feature = "default_dictionary")]
    /// # #[cfg(feature = "std_rng")]
    /// petnames.generate_one(2, ".");
    /// ```
    ///
    /// This is merely a convenience wrapper that applies the same predicate to
    /// the adjectives, adverbs, and names lists.
    ///
    pub fn retain<F>(&mut self, mut predicate: F)
    where
        F: FnMut(&str) -> bool,
    {
        self.adjectives.retain(|word| predicate(word));
        self.adverbs.retain(|word| predicate(word));
        self.names.retain(|word| predicate(word));
    }

    /// Calculate the cardinality of this `Petnames`.
    ///
    /// If this is low, names may be repeated by the generator with a higher
    /// frequency than your use-case may allow. If it is 0 (zero) the generator
    /// will panic (unless `words` is also zero).
    ///
    /// This can saturate. If the total possible combinations of words exceeds
    /// `u128::MAX` then this will return `u128::MAX`.
    pub fn cardinality(&self, words: u8) -> u128 {
        Lists(self, words)
            .map(|list| list.len() as u128)
            .fold1(u128::saturating_mul)
            .unwrap_or(0u128)
    }

    /// Generate a new petname.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let mut rng = rand::thread_rng();
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// petname::Petnames::default().generate(&mut rng, 7, ":");
    /// ```
    ///
    /// # Notes
    ///
    /// This may return fewer words than you request if one or more of the word
    /// lists are empty. For example, if there are no adverbs, requesting 3 or
    /// more words may still yield only "doubtful-salmon".
    ///
    pub fn generate<RNG>(&self, rng: &mut RNG, words: u8, separator: &str) -> String
    where
        RNG: rand::Rng,
    {
        itertools::Itertools::intersperse(
            Lists(self, words)
                .filter_map(|list| list.choose(rng))
                .cloned(),
            separator,
        )
        .collect::<String>()
    }

    /// Generate a single new petname.
    ///
    /// This is like `generate` but uses `rand::thread_rng` as the random
    /// source. For efficiency use `generate` when creating multiple names, or
    /// when you want to use a custom source of randomness.
    #[cfg(feature = "std_rng")]
    pub fn generate_one(&self, words: u8, separator: &str) -> String {
        self.generate(&mut rand::thread_rng(), words, separator)
    }

    /// Iterator yielding petnames.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let mut rng = rand::thread_rng();
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let petnames = petname::Petnames::default();
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let mut iter = petnames.iter(&mut rng, 4, "_");
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// println!("name: {}", iter.next().unwrap());
    /// ```
    ///
    pub fn iter<RNG>(&self, rng: &'a mut RNG, words: u8, separator: &str) -> Names<RNG>
    where
        RNG: rand::Rng,
    {
        Names {
            petnames: self,
            rng,
            words,
            separator: separator.to_string(),
        }
    }
}

#[cfg(feature = "default_dictionary")]
impl<'a> Default for Petnames<'a> {
    fn default() -> Self {
        Self::small()
    }
}

/// Iterator over a `Petnames`' word lists.
///
/// This yields the appropriate lists from which to select a word when
/// constructing a petname of `n` words. For example, if you want 3 words in
/// your petname, this will first yield the adverbs word list, then adjectives,
/// then names.
struct Lists<'a>(&'a Petnames<'a>, u8);

impl<'a> Iterator for Lists<'a> {
    type Item = &'a Words<'a>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, Some(self.1 as usize))
    }

    fn next(&mut self) -> Option<Self::Item> {
        let Self(petnames, ref mut word) = self;
        match word {
            0 => None,
            1 => {
                *word -= 1;
                Some(&petnames.names)
            }
            2 => {
                *word -= 1;
                Some(&petnames.adjectives)
            }
            _ => {
                *word -= 1;
                Some(&petnames.adverbs)
            }
        }
    }
}

/// Iterator yielding petnames.
pub struct Names<'a, RNG>
where
    RNG: rand::Rng,
{
    petnames: &'a Petnames<'a>,
    rng: &'a mut RNG,
    words: u8,
    separator: String,
}

impl<'a, RNG> Names<'a, RNG>
where
    RNG: rand::Rng,
{
    /// Calculate the cardinality of this iterator; see `Petnames::cardinality`.
    #[allow(dead_code)]
    pub fn cardinality(&self) -> u128 {
        self.petnames.cardinality(self.words)
    }
}

impl<'a, RNG> Iterator for Names<'a, RNG>
where
    RNG: rand::Rng,
{
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        Some(
            self.petnames
                .generate(self.rng, self.words, &self.separator),
        )
    }
}
<commit_msg>First go at a non-repeating petname iterator<commit_after>#![no_std]
//!
//! You can populate [`Petnames`] with your own word lists, but the word lists
//! from upstream [petname](https://github.com/dustinkirkland/petname) are
//! included with the `default_dictionary` feature (enabled by default). See
//! [`Petnames::small`], [`Petnames::medium`], and [`Petnames::large`] to select
//! a particular built-in word list, or use the [`Default`] implementation.
//!
//! The other thing you need is a random number generator from [rand][]:
//!
//! ```rust
//! let mut rng = rand::thread_rng();
//! let pname = petname::Petnames::default().generate(&mut rng, 7, ":");
//! ```
//!
//! It may be more convenient to use the default random number generator:
//!
//! ```rust
//! let pname = petname::Petnames::default().generate_one(7, ":");
//! ```
//!
//! There's a [convenience function][petname] that'll do all of this:
//!
//! ```rust
//! let pname = petname::petname(7, ":");
//! ```
//!
//! But the most flexible approach is to create an [`Iterator`] with
//! [`iter`][`Petnames::iter`]:
//!
//! ```rust
//! let mut rng = rand::thread_rng();
//! let petnames = petname::Petnames::default();
//! let ten_thousand_names: Vec<String> =
//!   petnames.iter(&mut rng, 3, "_").take(10000).collect();
//! ```
//!
//! You can modify the word lists to, for example, only use words beginning with
//! the letter "b":
//!
//! ```rust
//! let mut petnames = petname::Petnames::default();
//! petnames.retain(|s| s.starts_with("b"));
//! petnames.generate_one(3, ".");
//! ```
//!

extern crate alloc;

use alloc::{
    string::{String, ToString},
    vec::Vec,
};

use itertools::Itertools;
use rand::seq::SliceRandom;

/// Convenience function to generate a new petname from default word lists.
#[allow(dead_code)]
#[cfg(feature = "std_rng")]
#[cfg(feature = "default_dictionary")]
pub fn petname(words: u8, separator: &str) -> String {
    Petnames::new().generate_one(words, separator)
}

/// A word list.
pub type Words<'a> = Vec<&'a str>;

/// Word lists and the logic to combine them into _petnames_.
///
/// A _petname_ with `n` words will contain, in order:
///
///   * `n - 2` adverbs when `n >= 2`, otherwise 0 adverbs.
///   * 1 adjective when `n >= 2`, otherwise 0 adjectives.
///   * 1 name / noun when `n >= 1`, otherwise 0 names.
///
#[derive(Clone, Debug, PartialEq)]
pub struct Petnames<'a> {
    pub adjectives: Words<'a>,
    pub adverbs: Words<'a>,
    pub names: Words<'a>,
}

impl<'a> Petnames<'a> {
    /// Constructs a new `Petnames` from the default (small) word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn new() -> Self {
        Self::default()
    }

    /// Constructs a new `Petnames` from the small word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn small() -> Self {
        Self::init(
            include_str!("../words/small/adjectives.txt"),
            include_str!("../words/small/adverbs.txt"),
            include_str!("../words/small/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the medium word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn medium() -> Self {
        Self::init(
            include_str!("../words/medium/adjectives.txt"),
            include_str!("../words/medium/adverbs.txt"),
            include_str!("../words/medium/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the large word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn large() -> Self {
        Self::init(
            include_str!("../words/large/adjectives.txt"),
            include_str!("../words/large/adverbs.txt"),
            include_str!("../words/large/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the given word lists.
    ///
    /// The words are extracted from the given strings by splitting on whitespace.
    pub fn init(adjectives: &'a str, adverbs: &'a str, names: &'a str) -> Self {
        Self {
            adjectives: adjectives.split_whitespace().collect(),
            adverbs: adverbs.split_whitespace().collect(),
            names: names.split_whitespace().collect(),
        }
    }

    /// Keep words matching a predicate.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[cfg(feature = "default_dictionary")]
    /// let mut petnames = petname::Petnames::default();
    /// # #[cfg(feature = "default_dictionary")]
    /// petnames.retain(|s| s.starts_with("b"));
    /// # #[cfg(feature = "default_dictionary")]
    /// # #[cfg(feature = "std_rng")]
    /// petnames.generate_one(2, ".");
    /// ```
    ///
    /// This is merely a convenience wrapper that applies the same predicate to
    /// the adjectives, adverbs, and names lists.
    ///
    pub fn retain<F>(&mut self, mut predicate: F)
    where
        F: FnMut(&str) -> bool,
    {
        self.adjectives.retain(|word| predicate(word));
        self.adverbs.retain(|word| predicate(word));
        self.names.retain(|word| predicate(word));
    }

    /// Calculate the cardinality of this `Petnames`.
    ///
    /// If this is low, names may be repeated by the generator with a higher
    /// frequency than your use-case may allow. If it is 0 (zero) the generator
    /// will panic (unless `words` is also zero).
    ///
    /// This can saturate. If the total possible combinations of words exceeds
    /// `u128::MAX` then this will return `u128::MAX`.
    pub fn cardinality(&self, words: u8) -> u128 {
        Lists(self, words)
            .map(|list| list.len() as u128)
            .fold1(u128::saturating_mul)
            .unwrap_or(0u128)
    }

    /// Generate a new petname.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let mut rng = rand::thread_rng();
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// petname::Petnames::default().generate(&mut rng, 7, ":");
    /// ```
    ///
    /// # Notes
    ///
    /// This may return fewer words than you request if one or more of the word
    /// lists are empty. For example, if there are no adverbs, requesting 3 or
    /// more words may still yield only "doubtful-salmon".
    ///
    pub fn generate<RNG>(&self, rng: &mut RNG, words: u8, separator: &str) -> String
    where
        RNG: rand::Rng,
    {
        itertools::Itertools::intersperse(
            Lists(self, words)
                .filter_map(|list| list.choose(rng))
                .cloned(),
            separator,
        )
        .collect::<String>()
    }

    /// Generate a single new petname.
    ///
    /// This is like `generate` but uses `rand::thread_rng` as the random
    /// source. For efficiency use `generate` when creating multiple names, or
    /// when you want to use a custom source of randomness.
    #[cfg(feature = "std_rng")]
    pub fn generate_one(&self, words: u8, separator: &str) -> String {
        self.generate(&mut rand::thread_rng(), words, separator)
    }

    /// Iterator yielding petnames.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let mut rng = rand::thread_rng();
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let petnames = petname::Petnames::default();
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let mut iter = petnames.iter(&mut rng, 4, "_");
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// println!("name: {}", iter.next().unwrap());
    /// ```
    ///
    pub fn iter<RNG>(&self, rng: &'a mut RNG, words: u8, separator: &str) -> Names<RNG>
    where
        RNG: rand::Rng,
    {
        Names {
            petnames: self,
            rng,
            words,
            separator: separator.to_string(),
        }
    }

    /// Iterator yielding unique – i.e. non-repeating – petnames.
    pub fn iter_unique<RNG>(&'a self, rng: &'a mut RNG, words: u8, separator: &str) -> NamesUnique
    where
        RNG: rand::Rng,
    {
        let mut list_copies: Vec<Words> = Vec::with_capacity(words as usize);

        for list in Lists(self, words) {
            let mut list_copy: Vec<&str> = list.iter().map(|s| *s).collect();
            list_copy.shuffle(rng);
            list_copies.push(list_copy);
        }

        let mut iters: Vec<alloc::vec::IntoIter<&'a str>> = Vec::with_capacity(words as usize);
        for list_copy in list_copies.drain(..) {
            iters.push(list_copy.into_iter())
        }

        NamesUnique {
            iters: iters,
            separator: separator.to_string(),
        }
    }
}

#[cfg(feature = "default_dictionary")]
impl<'a> Default for Petnames<'a> {
    fn default() -> Self {
        Self::small()
    }
}

/// Iterator over a `Petnames`' word lists.
///
/// This yields the appropriate lists from which to select a word when
/// constructing a petname of `n` words. For example, if you want 3 words in
/// your petname, this will first yield the adverbs word list, then adjectives,
/// then names.
struct Lists<'a>(&'a Petnames<'a>, u8);

impl<'a> Iterator for Lists<'a> {
    type Item = &'a Words<'a>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, Some(self.1 as usize))
    }

    fn next(&mut self) -> Option<Self::Item> {
        let Self(petnames, ref mut word) = self;
        match word {
            0 => None,
            1 => {
                *word -= 1;
                Some(&petnames.names)
            }
            2 => {
                *word -= 1;
                Some(&petnames.adjectives)
            }
            _ => {
                *word -= 1;
                Some(&petnames.adverbs)
            }
        }
    }
}

/// Iterator yielding petnames.
pub struct Names<'a, RNG>
where
    RNG: rand::Rng,
{
    petnames: &'a Petnames<'a>,
    rng: &'a mut RNG,
    words: u8,
    separator: String,
}

impl<'a, RNG> Names<'a, RNG>
where
    RNG: rand::Rng,
{
    /// Calculate the cardinality of this iterator; see `Petnames::cardinality`.
    #[allow(dead_code)]
    pub fn cardinality(&self) -> u128 {
        self.petnames.cardinality(self.words)
    }
}

impl<'a, RNG> Iterator for Names<'a, RNG>
where
    RNG: rand::Rng,
{
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        Some(
            self.petnames
                .generate(self.rng, self.words, &self.separator),
        )
    }
}

/// Iterator yielding unique petnames.
pub struct NamesUnique<'a> {
    iters: Vec<alloc::vec::IntoIter<&'a str>>,
    separator: String,
}

impl<'a> Iterator for NamesUnique<'a> {
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        let words_options: Vec<Option<&str>> =
            self.iters.iter_mut().map(|iter| iter.next()).collect();
        let words: Vec<&str> = words_options.iter().filter_map(|wo| *wo).collect();

        if words_options.len() > words.len() {
            None
        } else {
            Some(
                itertools::Itertools::intersperse(words.iter().map(|s| *s), &self.separator)
                    .collect::<String>(),
            )
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg_attr(feature = "unstable", feature(cfg_target_feature, test, fn_must_use))]

//! A collection of strongly typed math tools for computer graphics with an inclination
//! towards 2d graphics and layout.
//!
//! All types are generic over the scalar type of their component (`f32`, `i32`, etc.),
//! and tagged with a generic Unit parameter which is useful to prevent mixing
//! values from different spaces. For example it should not be legal to translate
//! a screen-space position by a world-space vector and this can be expressed using
//! the generic Unit parameter.
//!
//! This unit system is not mandatory and all Typed* structures have an alias
//! with the default unit: `UnknownUnit`.
//! for example ```Point2D<T>``` is equivalent to ```TypedPoint2D<T, UnknownUnit>```.
//! Client code typically creates a set of aliases for each type and doesn't need
//! to deal with the specifics of typed units further. For example:
//!
//! ```rust
//! use euclid::*;
//! pub struct ScreenSpace;
//! pub type ScreenPoint = TypedPoint2D<f32, ScreenSpace>;
//! pub type ScreenSize = TypedSize2D<f32, ScreenSpace>;
//! pub struct WorldSpace;
//! pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
//! pub type ProjectionMatrix = TypedTransform3D<f32, WorldSpace, ScreenSpace>;
//! // etc...
//! ```
//!
//! All euclid types are marked `#[repr(C)]` in order to facilitate exposing them to
//! foreign function interfaces (provided the underlying scalar type is also `repr(C)`).
//!
//! Components are accessed in their scalar form by default for convenience, and most
//! types additionally implement strongly typed accessors which return typed ```Length``` wrappers.
//! For example:
//!
//! ```rust
//! # use euclid::*;
//! # pub struct WorldSpace;
//! # pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
//! let p = WorldPoint::new(0.0, 1.0, 1.0);
//! // p.x is an f32.
//! println!("p.x = {:?} ", p.x);
//! // p.x is a Length<f32, WorldSpace>.
//! println!("p.x_typed() = {:?} ", p.x_typed());
//! // Length::get returns the scalar value (f32).
//! assert_eq!(p.x, p.x_typed().get());
//! ```

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

extern crate num_traits;
#[cfg(test)]
extern crate rand;
#[cfg(feature = "unstable")]
extern crate test;

pub use length::Length;
pub use scale::TypedScale;
pub use transform2d::{Transform2D, TypedTransform2D};
pub use transform3d::{Transform3D, TypedTransform3D};
pub use point::{Point2D, Point3D, TypedPoint2D, TypedPoint3D, point2, point3};
pub use vector::{TypedVector2D, TypedVector3D, Vector2D, Vector3D, vec2, vec3};

pub use rect::{rect, Rect, TypedRect};
pub use rotation::{Angle, Rotation2D, Rotation3D, TypedRotation2D, TypedRotation3D};
pub use side_offsets::{SideOffsets2D, TypedSideOffsets2D};
pub use size::{Size2D, TypedSize2D, size2};
pub use trig::Trig;

pub mod approxeq;
pub mod num;
mod length;
#[macro_use]
mod macros;
mod transform2d;
mod transform3d;
mod point;
mod rect;
mod rotation;
mod scale;
mod side_offsets;
mod size;
mod trig;
mod vector;

/// The default unit.
#[derive(Clone, Copy)]
pub struct UnknownUnit;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type Matrix2D<T> = Transform2D<T>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type TypedMatrix2D<T, Src, Dst> = TypedTransform2D<T, Src, Dst>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type Matrix4D<T> = Transform3D<T>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type TypedMatrix4D<T, Src, Dst> = TypedTransform3D<T, Src, Dst>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type ScaleFactor<T, Src, Dst> = TypedScale<T, Src, Dst>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub use Angle as Radians;
<commit_msg>Auto merge of #273 - servo:features, r=jdm<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg_attr(feature = "unstable", feature(fn_must_use))]

//! A collection of strongly typed math tools for computer graphics with an inclination
//! towards 2d graphics and layout.
//!
//! All types are generic over the scalar type of their component (`f32`, `i32`, etc.),
//! and tagged with a generic Unit parameter which is useful to prevent mixing
//! values from different spaces. For example it should not be legal to translate
//! a screen-space position by a world-space vector and this can be expressed using
//! the generic Unit parameter.
//!
//! This unit system is not mandatory and all Typed* structures have an alias
//! with the default unit: `UnknownUnit`.
//! for example ```Point2D<T>``` is equivalent to ```TypedPoint2D<T, UnknownUnit>```.
//! Client code typically creates a set of aliases for each type and doesn't need
//! to deal with the specifics of typed units further. For example:
//!
//! ```rust
//! use euclid::*;
//! pub struct ScreenSpace;
//! pub type ScreenPoint = TypedPoint2D<f32, ScreenSpace>;
//! pub type ScreenSize = TypedSize2D<f32, ScreenSpace>;
//! pub struct WorldSpace;
//! pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
//! pub type ProjectionMatrix = TypedTransform3D<f32, WorldSpace, ScreenSpace>;
//! // etc...
//! ```
//!
//! All euclid types are marked `#[repr(C)]` in order to facilitate exposing them to
//! foreign function interfaces (provided the underlying scalar type is also `repr(C)`).
//!
//! Components are accessed in their scalar form by default for convenience, and most
//! types additionally implement strongly typed accessors which return typed ```Length``` wrappers.
//! For example:
//!
//! ```rust
//! # use euclid::*;
//! # pub struct WorldSpace;
//! # pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
//! let p = WorldPoint::new(0.0, 1.0, 1.0);
//! // p.x is an f32.
//! println!("p.x = {:?} ", p.x);
//! // p.x is a Length<f32, WorldSpace>.
//! println!("p.x_typed() = {:?} ", p.x_typed());
//! // Length::get returns the scalar value (f32).
//! assert_eq!(p.x, p.x_typed().get());
//! ```

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

extern crate num_traits;
#[cfg(test)]
extern crate rand;

pub use length::Length;
pub use scale::TypedScale;
pub use transform2d::{Transform2D, TypedTransform2D};
pub use transform3d::{Transform3D, TypedTransform3D};
pub use point::{Point2D, Point3D, TypedPoint2D, TypedPoint3D, point2, point3};
pub use vector::{TypedVector2D, TypedVector3D, Vector2D, Vector3D, vec2, vec3};

pub use rect::{rect, Rect, TypedRect};
pub use rotation::{Angle, Rotation2D, Rotation3D, TypedRotation2D, TypedRotation3D};
pub use side_offsets::{SideOffsets2D, TypedSideOffsets2D};
pub use size::{Size2D, TypedSize2D, size2};
pub use trig::Trig;

pub mod approxeq;
pub mod num;
mod length;
#[macro_use]
mod macros;
mod transform2d;
mod transform3d;
mod point;
mod rect;
mod rotation;
mod scale;
mod side_offsets;
mod size;
mod trig;
mod vector;

/// The default unit.
#[derive(Clone, Copy)]
pub struct UnknownUnit;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type Matrix2D<T> = Transform2D<T>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type TypedMatrix2D<T, Src, Dst> = TypedTransform2D<T, Src, Dst>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type Matrix4D<T> = Transform3D<T>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type TypedMatrix4D<T, Src, Dst> = TypedTransform3D<T, Src, Dst>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type ScaleFactor<T, Src, Dst> = TypedScale<T, Src, Dst>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub use Angle as Radians;
<|endoftext|>


<commit_before>//!
//! Currently this is a simlpe proof of concpet.
//!

extern crate roboime_next_protocol as protocol;
extern crate net2;
extern crate time;

use std::net::{UdpSocket, Ipv4Addr, SocketAddrV4};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread::spawn;
use std::process::ExitStatus;
use protocol::{parse_from_bytes, Message};
use protocol::messages_robocup_ssl_wrapper_legacy::SSL_WrapperPacket;
use protocol::grSim_Packet::grSim_Packet;
use protocol::grSim_Commands::grSim_Robot_Command;
use net2::{UdpBuilder, UdpSocketExt};
//use time::{Duration, SteadyTime, precise_time_s};
use time::{Duration, SteadyTime};

pub use self::error::{Result, Error, ErrorKind};
pub use subproc::{CommandExt, ChildExt};

mod error;
mod subproc;

/// - One thread will bind to 0.0.0.0 and join the multicast to receive and dispatch vision packets
///   in a loop;
/// - Another thread will buffer the dispatched packets and if more than 1s passes after the last
///   tick it will print the size of the buffer, clear it, and reset the tick;
/// - Wait for both looping threads to join.
///
pub fn demo() {
    let (tx, rx) = channel();
    let recv_thread = spawn(move || {
        println!("recv thread started");

        let iface = Ipv4Addr::new(0, 0, 0, 0);
        let addr = SocketAddrV4::new(iface, 10002);
        //let socket = match UdpSocket::bind("0.0.0.0:10005") {
        let socket = match UdpBuilder::new_v4().unwrap().reuse_address(true).unwrap().bind(addr) {
            Ok(s) => s,
            Err(e) => panic!("couldn't bind socket: {}", e),
        };
        println!("bound to {}", addr);

        let mcast_addr = Ipv4Addr::new(224, 5, 23, 2);
        match socket.join_multicast_v4(&mcast_addr, &iface) {
            Ok(()) => (),
            Err(e) => panic!("couldn't join multicast: {}", e),
        }
        println!("joined multicast {}", mcast_addr);

        // 1KB buffer
        let buf = &mut [0u8; 1024];
        loop {
            match socket.recv_from(buf) {
                Ok((size, _)) => {
                    //match parse_from_bytes::<SSL_WrapperPacket>(&buf[0..size]) {
                    match parse_from_bytes(&buf[0..size]) {
                        Ok(packet) => match tx.send(packet) {
                            Ok(()) => {}
                            Err(e) => {
                                println!("couldn't send datagram to other thread: {}", e);
                                break;
                            }
                        },
                        Err(e) => {
                            println!("couldn't parse datagram: {}", e);
                        }
                    }
                },
                Err(e) => {
                    println!("couldn't receive datagram: {}", e);
                }
            }
        }
    });

    let (tx2, rx2) = channel();
    let work_thread = spawn(move || {
        match child_proc(rx, tx2) {
            Ok(s) => {
                println!("child subproc exited with: {}", s);
            }
            Err(e) => {
                println!("child subproc errored: {}", e);
            }
        }
    });

    let send_thread = spawn(move || {
        let iface = Ipv4Addr::new(0, 0, 0, 0);
        let addr = SocketAddrV4::new(iface, 0);
        let socket = match UdpSocket::bind(addr) {
            Ok(s) => s,
            Err(e) => panic!("couldn't bind socket: {}", e),
        };
        println!("send socket bound to {}", addr);

        let grsim_ip = Ipv4Addr::new(192, 168, 91, 92);
        let grsim_addr = SocketAddrV4::new(grsim_ip, 20011);

        let mut last_time = SteadyTime::now();
        let mut counter = 0;

        loop {
            match rx2.recv() {
                Ok(ref bytes) => {
                    match socket.send_to(bytes, grsim_addr) {
                        //Ok(size) => { println!("{} bytes sent", size); }
                        Ok(_) => { counter += 1; },
                        Err(e) => { println!("error sending bytes to grSim: {}", e); }
                    }
                }
                Err(e) => {
                    println!("error receiving from work_thread: {}", e);
                    break;
                }
            }

            let next_time = SteadyTime::now();
            let delta = next_time - last_time;
            if delta >= Duration::seconds(1) {
                println!("sent packets: {}, delta: {}", counter, delta);
                counter = 0;
                last_time = next_time;
            }
        }
    });

    recv_thread.join().unwrap();
    work_thread.join().unwrap();
    send_thread.join().unwrap();
}

fn child_proc(rx: Receiver<SSL_WrapperPacket>, tx: Sender<Vec<u8>>) -> Result<ExitStatus> {
    use std::process::Command;
    use std::io::prelude::*;
    use std::io::BufReader;

    println!("work thread started");

    let mut child = try!(Command::new("./demo-ai").piped_spawn());
    println!("running subproc");

    fn new_err(msg: &str) -> error::Error {
        error::Error::new(error::ErrorKind::AiProtocol, msg.to_string())
    }

    try!(child.map_all_pipes(|child_in, child_out, child_err| {
        let mut lines = BufReader::new(child_out).lines();

        try!(writeln!(child_in, "ROBOIME_INTEL_PROTOCOL_VERSION 1"));
        {
            let line = try!(match lines.next() {
                Some(thing) => thing,
                None => {
                    return Err(new_err("no output"));
                }
            });
            match line.as_ref() {
                "COMPATIBLE 1" => {
                    println!("AI is compatible");
                },
                s if s.starts_with("NOT_COMPATIBLE") => {
                    println!("AI is not compatible");
                    return Ok(());
                },
                _ => {
                    return Err(new_err("invalid version confirmation"));
                }
            }
        }

        // TODO: get these from the geometry, or better, from a game state

        // FIELD_WIDTH
        try!(writeln!(child_in, "4.000"));
        // FIELD_HEIGHT
        try!(writeln!(child_in, "6.000"));
        // GOAL_WIDTH
        try!(writeln!(child_in, "0.700"));
        // CENTER_CIRCLE_RADIUS
        try!(writeln!(child_in, "0.500"));
        // DEFENSE_RADIUS
        try!(writeln!(child_in, "0.500"));
        // DEFENSE_STRETCH
        try!(writeln!(child_in, "0.350"));
        // FREE_KICK_FROM_DEFENSE_DIST
        try!(writeln!(child_in, "0.700"));
        // PENALTY_SPOT_FROM_FIELD_LINE_DIST
        try!(writeln!(child_in, "0.450"));
        // PENALTY_LINE_FROM_SPOT_DIST
        try!(writeln!(child_in, "0.350"));

        //for line in BufReader::new(child_err).lines() {
        //    println!("got: {:?}", line);
        //}

        let mut counter: u64 = 0;
        loop {
            let packet = rx.recv().unwrap();
            if !packet.has_detection() {
                println!("geometry packet");
                continue;
            }
            let detection = packet.get_detection();

            //let timestamp = precise_time_s();
            let timestamp = detection.get_t_capture();

            // COUNTER
            try!(writeln!(child_in, "{}", counter));
            counter += 1;

            // TIMESTAMP
            try!(writeln!(child_in, "{}", timestamp));

            // OUR_SCORE OPPONENT_SCORE
            try!(writeln!(child_in, "0 0"));

            // REF_STATE <REF_TIME_LEFT|-1>
            try!(writeln!(child_in, "N -1"));

            let balls = detection.get_balls();
            let ball = &balls[0]; // TODO: get best ball

            // BALL_X BALL_Y BALL_VX BALL_VY
            try!(writeln!(child_in, "{} {} 0 0", ball.get_x(), ball.get_y()));

            // GOALKEEPER_ID
            try!(writeln!(child_in, "0"));

            let robots_yellow = detection.get_robots_yellow();
            let robots_blue = detection.get_robots_blue();

            // NUM_ROBOTS
            try!(writeln!(child_in, "{}", robots_yellow.len()));

            // OPPONENT_NUM_ROBOTS
            try!(writeln!(child_in, "{}", robots_blue.len()));

            for robot in robots_yellow {
                // [ROBOT_ID ROBOT_X ROBOT_Y ROBOT_W ROBOT_VX ROBOT_VY ROBOT_VW] x NUM_ROBOTS
                try!(writeln!(child_in,
                         "{} {} {} {} 0 0 0",
                         robot.get_robot_id(),
                         robot.get_x(),
                         robot.get_y(),
                         robot.get_orientation()
                        ));
            }

            for robot in robots_blue {
                // [ROBOT_ID ROBOT_X ROBOT_Y ROBOT_W ROBOT_VX ROBOT_VY ROBOT_VW] x OPPONENT_NUM_ROBOTS
                try!(writeln!(child_in,
                         "{} {} {} {} 0 0 0",
                         robot.get_robot_id(),
                         robot.get_x(),
                         robot.get_y(),
                         robot.get_orientation()
                        ));
            }

            {
                let line = try!(match lines.next() {
                    Some(thing) => thing,
                    None => { break; }
                });
                assert_eq!(line, format!("C {}", counter));
            }

            let mut packet = grSim_Packet::new();
            {
                let commands = packet.mut_commands();
                commands.set_timestamp(timestamp);
                commands.set_isteamyellow(true);
                let robot_commands = commands.mut_robot_commands();

                for robot in robots_yellow {
                    let mut robot_command = grSim_Robot_Command::new();
                    let robot_id = robot.get_robot_id();

                    let line = try!(match lines.next() {
                        Some(thing) => thing,
                        None => { break; }
                    });

                    let vars: Vec<_> = line.split(' ').collect();
                    assert_eq!(vars.len(), 6);

                    let v_tan:  f32 = try!(vars[0].parse());
                    let v_norm: f32 = try!(vars[1].parse());
                    let v_ang:  f32 = try!(vars[2].parse());
                    let kick_x: f32 = try!(vars[3].parse());
                    let kick_z: f32 = try!(vars[4].parse());
                    let spin = try!(vars[5].parse::<i32>()) == 1;

                    robot_command.set_id(robot_id);
                    robot_command.set_kickspeedx(kick_x);
                    robot_command.set_kickspeedz(kick_z);
                    robot_command.set_veltangent(v_tan);
                    robot_command.set_velnormal(v_norm);
                    robot_command.set_velangular(v_ang);
                    robot_command.set_spinner(spin);
                    robot_command.set_wheelsspeed(false);
                    robot_commands.push(robot_command);
                }
            }

            match packet.write_to_bytes() {
                Ok(bytes) => {
                    match tx.send(bytes) {
                        Ok(_) => (),
                        Err(e) => {
                            println!("error sending to send_thread: {}", e);
                        }
                    }
                }
                Err(e) => {
                    println!("error writing protobuf packet to byes: {}", e);
                }
            }
        }

        for line in BufReader::new(child_err).lines() {
            println!("{}", try!(line));
        }

        Ok(())
    }));

    Ok(try!(child.wait()))
}
<commit_msg>Saner hardcoded IP.<commit_after>//!
//! Currently this is a simlpe proof of concpet.
//!

extern crate roboime_next_protocol as protocol;
extern crate net2;
extern crate time;

use std::net::{UdpSocket, Ipv4Addr, SocketAddrV4};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread::spawn;
use std::process::ExitStatus;
use protocol::{parse_from_bytes, Message};
use protocol::messages_robocup_ssl_wrapper_legacy::SSL_WrapperPacket;
use protocol::grSim_Packet::grSim_Packet;
use protocol::grSim_Commands::grSim_Robot_Command;
use net2::{UdpBuilder, UdpSocketExt};
//use time::{Duration, SteadyTime, precise_time_s};
use time::{Duration, SteadyTime};

pub use self::error::{Result, Error, ErrorKind};
pub use subproc::{CommandExt, ChildExt};

mod error;
mod subproc;

/// - One thread will bind to 0.0.0.0 and join the multicast to receive and dispatch vision packets
///   in a loop;
/// - Another thread will buffer the dispatched packets and if more than 1s passes after the last
///   tick it will print the size of the buffer, clear it, and reset the tick;
/// - Wait for both looping threads to join.
///
pub fn demo() {
    let (tx, rx) = channel();
    let recv_thread = spawn(move || {
        println!("recv thread started");

        let iface = Ipv4Addr::new(0, 0, 0, 0);
        let addr = SocketAddrV4::new(iface, 10002);
        //let socket = match UdpSocket::bind("0.0.0.0:10005") {
        let socket = match UdpBuilder::new_v4().unwrap().reuse_address(true).unwrap().bind(addr) {
            Ok(s) => s,
            Err(e) => panic!("couldn't bind socket: {}", e),
        };
        println!("bound to {}", addr);

        let mcast_addr = Ipv4Addr::new(224, 5, 23, 2);
        match socket.join_multicast_v4(&mcast_addr, &iface) {
            Ok(()) => (),
            Err(e) => panic!("couldn't join multicast: {}", e),
        }
        println!("joined multicast {}", mcast_addr);

        // 1KB buffer
        let buf = &mut [0u8; 1024];
        loop {
            match socket.recv_from(buf) {
                Ok((size, _)) => {
                    //match parse_from_bytes::<SSL_WrapperPacket>(&buf[0..size]) {
                    match parse_from_bytes(&buf[0..size]) {
                        Ok(packet) => match tx.send(packet) {
                            Ok(()) => {}
                            Err(e) => {
                                println!("couldn't send datagram to other thread: {}", e);
                                break;
                            }
                        },
                        Err(e) => {
                            println!("couldn't parse datagram: {}", e);
                        }
                    }
                },
                Err(e) => {
                    println!("couldn't receive datagram: {}", e);
                }
            }
        }
    });

    let (tx2, rx2) = channel();
    let work_thread = spawn(move || {
        match child_proc(rx, tx2) {
            Ok(s) => {
                println!("child subproc exited with: {}", s);
            }
            Err(e) => {
                println!("child subproc errored: {}", e);
            }
        }
    });

    let send_thread = spawn(move || {
        let iface = Ipv4Addr::new(0, 0, 0, 0);
        let addr = SocketAddrV4::new(iface, 0);
        let socket = match UdpSocket::bind(addr) {
            Ok(s) => s,
            Err(e) => panic!("couldn't bind socket: {}", e),
        };
        println!("send socket bound to {}", addr);

        let grsim_ip = Ipv4Addr::new(127, 0, 0, 1);
        let grsim_addr = SocketAddrV4::new(grsim_ip, 20011);

        let mut last_time = SteadyTime::now();
        let mut counter = 0;

        loop {
            match rx2.recv() {
                Ok(ref bytes) => {
                    match socket.send_to(bytes, grsim_addr) {
                        //Ok(size) => { println!("{} bytes sent", size); }
                        Ok(_) => { counter += 1; },
                        Err(e) => { println!("error sending bytes to grSim: {}", e); }
                    }
                }
                Err(e) => {
                    println!("error receiving from work_thread: {}", e);
                    break;
                }
            }

            let next_time = SteadyTime::now();
            let delta = next_time - last_time;
            if delta >= Duration::seconds(1) {
                println!("sent packets: {}, delta: {}", counter, delta);
                counter = 0;
                last_time = next_time;
            }
        }
    });

    recv_thread.join().unwrap();
    work_thread.join().unwrap();
    send_thread.join().unwrap();
}

fn child_proc(rx: Receiver<SSL_WrapperPacket>, tx: Sender<Vec<u8>>) -> Result<ExitStatus> {
    use std::process::Command;
    use std::io::prelude::*;
    use std::io::BufReader;

    println!("work thread started");

    let mut child = try!(Command::new("./demo-ai").piped_spawn());
    println!("running subproc");

    fn new_err(msg: &str) -> error::Error {
        error::Error::new(error::ErrorKind::AiProtocol, msg.to_string())
    }

    try!(child.map_all_pipes(|child_in, child_out, child_err| {
        let mut lines = BufReader::new(child_out).lines();

        try!(writeln!(child_in, "ROBOIME_INTEL_PROTOCOL_VERSION 1"));
        {
            let line = try!(match lines.next() {
                Some(thing) => thing,
                None => {
                    return Err(new_err("no output"));
                }
            });
            match line.as_ref() {
                "COMPATIBLE 1" => {
                    println!("AI is compatible");
                },
                s if s.starts_with("NOT_COMPATIBLE") => {
                    println!("AI is not compatible");
                    return Ok(());
                },
                _ => {
                    return Err(new_err("invalid version confirmation"));
                }
            }
        }

        // TODO: get these from the geometry, or better, from a game state

        // FIELD_WIDTH
        try!(writeln!(child_in, "4.000"));
        // FIELD_HEIGHT
        try!(writeln!(child_in, "6.000"));
        // GOAL_WIDTH
        try!(writeln!(child_in, "0.700"));
        // CENTER_CIRCLE_RADIUS
        try!(writeln!(child_in, "0.500"));
        // DEFENSE_RADIUS
        try!(writeln!(child_in, "0.500"));
        // DEFENSE_STRETCH
        try!(writeln!(child_in, "0.350"));
        // FREE_KICK_FROM_DEFENSE_DIST
        try!(writeln!(child_in, "0.700"));
        // PENALTY_SPOT_FROM_FIELD_LINE_DIST
        try!(writeln!(child_in, "0.450"));
        // PENALTY_LINE_FROM_SPOT_DIST
        try!(writeln!(child_in, "0.350"));

        //for line in BufReader::new(child_err).lines() {
        //    println!("got: {:?}", line);
        //}

        let mut counter: u64 = 0;
        loop {
            let packet = rx.recv().unwrap();
            if !packet.has_detection() {
                println!("geometry packet");
                continue;
            }
            let detection = packet.get_detection();

            //let timestamp = precise_time_s();
            let timestamp = detection.get_t_capture();

            // COUNTER
            try!(writeln!(child_in, "{}", counter));
            counter += 1;

            // TIMESTAMP
            try!(writeln!(child_in, "{}", timestamp));

            // OUR_SCORE OPPONENT_SCORE
            try!(writeln!(child_in, "0 0"));

            // REF_STATE <REF_TIME_LEFT|-1>
            try!(writeln!(child_in, "N -1"));

            let balls = detection.get_balls();
            let ball = &balls[0]; // TODO: get best ball

            // BALL_X BALL_Y BALL_VX BALL_VY
            try!(writeln!(child_in, "{} {} 0 0", ball.get_x(), ball.get_y()));

            // GOALKEEPER_ID
            try!(writeln!(child_in, "0"));

            let robots_yellow = detection.get_robots_yellow();
            let robots_blue = detection.get_robots_blue();

            // NUM_ROBOTS
            try!(writeln!(child_in, "{}", robots_yellow.len()));

            // OPPONENT_NUM_ROBOTS
            try!(writeln!(child_in, "{}", robots_blue.len()));

            for robot in robots_yellow {
                // [ROBOT_ID ROBOT_X ROBOT_Y ROBOT_W ROBOT_VX ROBOT_VY ROBOT_VW] x NUM_ROBOTS
                try!(writeln!(child_in,
                         "{} {} {} {} 0 0 0",
                         robot.get_robot_id(),
                         robot.get_x(),
                         robot.get_y(),
                         robot.get_orientation()
                        ));
            }

            for robot in robots_blue {
                // [ROBOT_ID ROBOT_X ROBOT_Y ROBOT_W ROBOT_VX ROBOT_VY ROBOT_VW] x OPPONENT_NUM_ROBOTS
                try!(writeln!(child_in,
                         "{} {} {} {} 0 0 0",
                         robot.get_robot_id(),
                         robot.get_x(),
                         robot.get_y(),
                         robot.get_orientation()
                        ));
            }

            {
                let line = try!(match lines.next() {
                    Some(thing) => thing,
                    None => { break; }
                });
                assert_eq!(line, format!("C {}", counter));
            }

            let mut packet = grSim_Packet::new();
            {
                let commands = packet.mut_commands();
                commands.set_timestamp(timestamp);
                commands.set_isteamyellow(true);
                let robot_commands = commands.mut_robot_commands();

                for robot in robots_yellow {
                    let mut robot_command = grSim_Robot_Command::new();
                    let robot_id = robot.get_robot_id();

                    let line = try!(match lines.next() {
                        Some(thing) => thing,
                        None => { break; }
                    });

                    let vars: Vec<_> = line.split(' ').collect();
                    assert_eq!(vars.len(), 6);

                    let v_tan:  f32 = try!(vars[0].parse());
                    let v_norm: f32 = try!(vars[1].parse());
                    let v_ang:  f32 = try!(vars[2].parse());
                    let kick_x: f32 = try!(vars[3].parse());
                    let kick_z: f32 = try!(vars[4].parse());
                    let spin = try!(vars[5].parse::<i32>()) == 1;

                    robot_command.set_id(robot_id);
                    robot_command.set_kickspeedx(kick_x);
                    robot_command.set_kickspeedz(kick_z);
                    robot_command.set_veltangent(v_tan);
                    robot_command.set_velnormal(v_norm);
                    robot_command.set_velangular(v_ang);
                    robot_command.set_spinner(spin);
                    robot_command.set_wheelsspeed(false);
                    robot_commands.push(robot_command);
                }
            }

            match packet.write_to_bytes() {
                Ok(bytes) => {
                    match tx.send(bytes) {
                        Ok(_) => (),
                        Err(e) => {
                            println!("error sending to send_thread: {}", e);
                        }
                    }
                }
                Err(e) => {
                    println!("error writing protobuf packet to byes: {}", e);
                }
            }
        }

        for line in BufReader::new(child_err).lines() {
            println!("{}", try!(line));
        }

        Ok(())
    }));

    Ok(try!(child.wait()))
}
<|endoftext|>