<commit_before>use std::io::Cursor;

use kuchiki::NodeRef;
use kuchiki::NodeDataRef;
use kuchiki::NodeData;
use kuchiki::ElementData;

use model::ListTopicItem;
use model::ListTopicTitleItem;
use model::ListTopicAuthorItem;
use model::ShowItem;
use model::ShowReplyItem;
use model::UrlQueryItem;
use reply_model::*;

use regex::Regex;
use url::Url;
use std::collections::HashMap;

#[derive(Clone)]
pub struct Show { }

impl Show {
    pub fn new() -> Self {
        Show {}
    }

    pub fn build(&mut self, document: &NodeRef,  url: &str) -> Result<ShowItem, &'static str> {

        let url_query = self.parse_url_query_item(&url);

        let (title, reply_count) = match self.parse_title_and_reply_count(&document, &url) {
            Ok((title,reply_count)) => (title, reply_count),
            Err(e) =>  {
                error!("{}", e);
                return Err(e)
            }
        };

        let (page, max_page) = {

            let page_select_option = document.select("select[name='page']").ok().map_or(None, |x| x.last());

            if page_select_option.is_none() {
                return Err("fail to build page and max_page, reason: 'page_select' not found");
            }

            let page_select = page_select_option.unwrap();

            let page_str_option = page_select.as_node().select("option[selected='selected']").ok().map_or(None, |mut x| x.next());

            if page_str_option.is_none() {
                return Err("fail to build page and max_page, reason: 'page_str' not found");
            }

            let page_str = page_str_option.unwrap();

            let max_page_str_option = page_select.as_node().select("option").ok().map_or(None, |x| x.last());

            if max_page_str_option.is_none() {
                return Err("fail to build page and max_page, reason: 'max_page_str' not found");
            }

            let max_page_str = max_page_str_option.unwrap();

            let page = page_str.text_contents().trim().to_string().parse::<usize>().unwrap_or(0);
            let max_page = max_page_str.text_contents()
                                       .trim()
                                       .to_string()
                                       .parse::<usize>()
                                       .unwrap_or(0);

            (page, max_page)
        };

        let replies = {
            let replies_option = self.parse_show_reply_items(&document);

            if replies_option.is_err() {
                let e = replies_option.err().unwrap();
                error!("{:?}", e);
                return Err(e);
            }

            replies_option.unwrap()
        };

        let show_item = ShowItem {
            url_query: url_query,
            replies: replies,
            page: page,
            max_page: max_page,
            reply_count: String::from(reply_count),
            title: String::from(title),
        };

        Ok(show_item)
    }

}

impl Show {

    fn parse_url_query_item(&self, url_str: &str) -> UrlQueryItem {
        let url = Url::parse(&url_str).expect("fail to parse url query item, reason: invalid url");
        let query = url.query().expect("fail to parse url query item, reason: invalid url query");
        let re = Regex::new(r"(\\?|&)(?P<key>[^&=]+)=(?P<value>[^&]+)").expect("fail to parse url query item, reason: invalid regex");

        let (channel, message) = {

            let mut map = HashMap::new();

            for cap in re.captures_iter(query) {
                let key = cap.name("key").unwrap_or("").to_string();
                let value = cap.name("value").unwrap_or("").to_string();
                map.entry(key).or_insert(value);
            }

            if map.len() < 2 {
                panic!("length of map is invalid.")
            }

            (
                map.get("type").expect("fail to parse url query item, reason: can not get value of 'type' attribute").to_string(),
                map.get("message").expect("fail to parse url query item, reason: can not get value of 'message' attribute").to_string()
            )
        };

        UrlQueryItem {
            channel: String::from(channel),
            message: String::from(message)
        }
    }

    fn parse_title_and_reply_count (&self, document: &NodeRef,  url: &str) -> Result<(String, String), &'static str> {

        return match document.select(".repliers tr") {
            Ok(mut trs) => {
                return match trs.next()  {
                    Some(repliers_tr) => {

                        let repliers_header_option = repliers_tr.as_node().select(".repliers_header").ok().map_or(None, |x| x.last() );

                        if repliers_header_option.is_none() {
                            return Err("fail to build title and reply_count, reason: 'repliers_header' not found");
                        }

                        let repliers_header = repliers_header_option.unwrap();

                        let divs_option = repliers_header.as_node().select("div").ok().map_or(None, |x| Some(x.collect::<Vec<_>>()));

                        if divs_option.is_none() {
                            return Err("fail to build title and reply_count, reason: 'divs' not found");
                        }

                        let divs = divs_option.unwrap();

                        let mut divs_enumerator = divs.iter().enumerate();

                        let count = divs_enumerator.clone().count();
                        if  count < 2 {
                            error!("length of topic_data is invalid. length: {}", count);
                            return Err(&"length of topic_data is invalid.");
                        }

                        let title_option = match divs_enumerator.clone().filter(|&(i, _)| i == 0).map(|(i, e)| (i,e)).next() {
                            Some((i, div)) => {
                                info!("{} => {:?}", i, div.text_contents());
                                Some(div.text_contents().trim().to_string())
                            },
                            None => None
                        };

                        let reply_count = match divs_enumerator.clone().filter(|&(i, _)| i == 1).map(|(i, e)| (i,e)).next() {
                            Some((i, div)) => {
                                info!("{} => {:?}", i, div.text_contents());
                                let re = Regex::new(r"^(?P<count>\d+)個回應$").expect("fail to build title and reply_count, reason: invalid regex");
                                let s_trimmed = div.text_contents().trim().to_string();
                                let cap_option = re.captures(&s_trimmed);
                                if cap_option.is_none() {
                                    None
                                } else {
                                    Some(cap_option.unwrap().name("count").unwrap_or("0").to_string())
                                }
                            },
                            None => None
                        };

                        if  title_option.is_none() || reply_count.is_none() {
                            return Err(&"fail to build title and reply_count, reason: 'topic_data' not found");
                        }

                        Ok(
                            (
                                title_option.unwrap().to_string(),
                                reply_count.unwrap().to_string()
                            )
                        )
                    },
                    None => Err(&"fail to build title and reply_count, reason: 'repliers_tr' not found")
                }
            },
            Err(e) =>  Err("fail to build title and reply_count, reason: 'repliers_tr' not found")
        };

    }

    fn parse_show_reply_items(&self, document: &NodeRef) -> Result<Vec<ShowReplyItem>, &'static str>  {

        let replies_data_option = document.select(".repliers tr[userid][username]").ok().map_or(None, |x| Some(x.collect::<Vec<_>>()) );

        if replies_data_option.is_none() {
            return Err(&"fail to parse show reply items, reason: 'replies_data' not found");
        }

        let replies_data = replies_data_option.unwrap();

        let show_replies = replies_data.iter().enumerate().map(reply_items_handler).collect::<Vec<_>>();

        let err_show_reply_option = show_replies.iter().filter(|x| x.is_err()).next();

        if err_show_reply_option.is_some() {
            return Err(&"fail to parse show reply items, reason: 'error show reply item' was found");
        }

        let result = show_replies.iter().map(|x| x.clone().unwrap() ).collect::<Vec<_>>();

        Ok(result)
    }
}

fn reply_items_handler((index,tr): (usize, &::kuchiki::NodeDataRef<::kuchiki::ElementData>)) -> Result<ShowReplyItem, &'static str> {
    let tr_attrs = (&tr.attributes).borrow();
    let userid_option = tr_attrs.get("userid");

    if userid_option.is_none() {
        return Err("fail to parse show reply item, reason: 'userid' not found");
    }

    let userid = userid_option.unwrap();

    let username_option = tr_attrs.get("username");

    if username_option.is_none() {
        return Err("fail to parse show reply item, reason: 'userame' not found");
    }

    let username = username_option.unwrap();

    let content_elm_option = tr.as_node().select(".repliers_right .ContentGrid").ok().map_or(None, |mut x| x.next());

    if content_elm_option.is_none() {
        return Err("fail to parse show reply item, reason: 'content_elm' not found");
    }
    let content_elm = content_elm_option.unwrap();

    let mut buff = Cursor::new(Vec::new());
    let serialize_result = content_elm.as_node().serialize(&mut buff);
    let vec = buff.into_inner();
    let content_result = String::from_utf8(vec);

    if content_result.is_err() {
        return Err("fail to parse show reply item, reason: 'content' invalid");
    }

    let content = content_result.unwrap();

    let datatime_option = tr.as_node().select(".repliers_right span").ok()
                    .map_or(None, |mut x| x.last() )
                    .map_or(None, |mut x| Some(x.text_contents()));

    if datatime_option.is_none() {
        return Err("fail to parse show reply item, reason: 'datatime' not found");
    }

    let datatime = datatime_option.unwrap();

    let mut vec: Vec<NodeType> = Vec::new();

    vec = recursive(content_elm.as_node());

    Ok(
        ShowReplyItem {
            userid: String::from(userid),
            username: String::from(username),
            content: String::from(content),
            body: vec,
            published_at: String::from(datatime),
        }
    )
}

fn recursive(elm: &NodeRef) -> Vec<NodeType> {

    let mut vec: Vec<NodeType> = Vec::new();

    for (index, child) in elm.children().enumerate() {
        // println!("[{}] => {:?}", index, child);
        let node_data = child.data().clone();

        match node_data {
            NodeData::Element(element_data) => {
                // println!("[{}] => [ELEMENT] => {:?}", index, element_data);
                // println!("[{}] => [ELEMENT] => {:?}", index, child);

                if element_data.name.local.trim().eq("blockquote") {

                    // println!("[{}] => [ELEMENT] => {:?}", index, child.children());
                    let subvec = recursive(&child);
                    let node = NodeType::BlockQuote(BlockQuoteNode { data: subvec });
                    vec.push(node);
                } else if element_data.name.local.trim().eq("br") {
                    let node = NodeType::Br(BrNode {});
                    vec.push(node);
                } else if element_data.name.local.trim().eq("img") {

                    let attrs = (&element_data.attributes).borrow();
                    let url = attrs.get("src").unwrap_or("");
                    let alt = attrs.get("alt").unwrap_or("");
                    let node = NodeType::Image(ImageNode { data: url.to_string(), alt: alt.to_string() });
                    vec.push(node);

                } else {
                    // println!("[{}] => [ELEMENT] => {:?}", index, child);
                    let mut subvec = recursive(&child);
                    vec.append(&mut subvec);
                }
            }
            NodeData::Text(rc) => {
                // println!("[{}] => [TEXT] => {:?}", index, rc);
                let d = rc.clone();
                let b = d.borrow();

                let s = b.trim().to_string();

                if s == "\n" {
                    // s = "\\n".to_string()
                    continue;
                }

                let node = NodeType::Text(TextNode { data: s });
                vec.push(node);
            }
            _ => {}
        }
    }
    vec
}
<commit_msg>refactor return a Result trait from parse_url_query_item + less use expect<commit_after>use std::io::Cursor;

use kuchiki::NodeRef;
use kuchiki::NodeDataRef;
use kuchiki::NodeData;
use kuchiki::ElementData;

use model::ListTopicItem;
use model::ListTopicTitleItem;
use model::ListTopicAuthorItem;
use model::ShowItem;
use model::ShowReplyItem;
use model::UrlQueryItem;
use reply_model::*;

use regex::Regex;
use url::Url;
use std::collections::HashMap;

#[derive(Clone)]
pub struct Show { }

impl Show {
    pub fn new() -> Self {
        Show {}
    }

    pub fn build(&mut self, document: &NodeRef,  url: &str) -> Result<ShowItem, &'static str> {

        let url_query = match self.parse_url_query_item(&url) {
            Ok(url_query) => url_query,
            Err(e) =>  {
                error!("{}", e);
                return Err(e)
            }
        };

        let (title, reply_count) = match self.parse_title_and_reply_count(&document, &url) {
            Ok((title,reply_count)) => (title, reply_count),
            Err(e) =>  {
                error!("{}", e);
                return Err(e)
            }
        };

        let (page, max_page) = {

            let page_select_option = document.select("select[name='page']").ok().map_or(None, |x| x.last());

            if page_select_option.is_none() {
                return Err("fail to build page and max_page, reason: 'page_select' not found");
            }

            let page_select = page_select_option.unwrap();

            let page_str_option = page_select.as_node().select("option[selected='selected']").ok().map_or(None, |mut x| x.next());

            if page_str_option.is_none() {
                return Err("fail to build page and max_page, reason: 'page_str' not found");
            }

            let page_str = page_str_option.unwrap();

            let max_page_str_option = page_select.as_node().select("option").ok().map_or(None, |x| x.last());

            if max_page_str_option.is_none() {
                return Err("fail to build page and max_page, reason: 'max_page_str' not found");
            }

            let max_page_str = max_page_str_option.unwrap();

            let page = page_str.text_contents().trim().to_string().parse::<usize>().unwrap_or(0);
            let max_page = max_page_str.text_contents()
                                       .trim()
                                       .to_string()
                                       .parse::<usize>()
                                       .unwrap_or(0);

            (page, max_page)
        };

        let replies = {
            let replies_option = self.parse_show_reply_items(&document);

            if replies_option.is_err() {
                let e = replies_option.err().unwrap();
                error!("{:?}", e);
                return Err(e);
            }

            replies_option.unwrap()
        };

        let show_item = ShowItem {
            url_query: url_query,
            replies: replies,
            page: page,
            max_page: max_page,
            reply_count: String::from(reply_count),
            title: String::from(title),
        };

        Ok(show_item)
    }

}

impl Show {

    fn parse_url_query_item(&self, url_str: &str) -> Result<UrlQueryItem, &'static str> {

        let url_option = Url::parse(&url_str);
        if url_option.is_err() {
            return Err("fail to parse url query item, reason: invalid url");
        }
        let url = url_option.unwrap();

        let query_option = url.query();
        if query_option.is_none() {
            return Err("fail to parse url query item, reason: invalid url query");
        }
        let query = query_option.unwrap();

        let re = Regex::new(r"(\\?|&)(?P<key>[^&=]+)=(?P<value>[^&]+)").expect("fail to parse url query item, reason: invalid regex");

        let (channel, message) = {

            let mut map = HashMap::new();

            for cap in re.captures_iter(query) {
                let key = cap.name("key").unwrap_or("").to_string();
                let value = cap.name("value").unwrap_or("").to_string();
                map.entry(key).or_insert(value);
            }

            let count = map.len();
            if count < 2 {
                error!("length of map is invalid. length: {}", count);
                return Err(&"length of map is invalid.");
            }

            let type_option = map.get("type");
            if type_option.is_none() {
                return Err(&"fail to parse url query item, reason: can not get value of 'type' attribute");
            }

            let message_option = map.get("message");
            if message_option.is_none() {
                return Err(&"fail to parse url query item, reason: can not get value of 'message' attribute");
            }

            (
                type_option.unwrap().to_string(),
                message_option.unwrap().to_string()
            )
        };

        Ok(
            UrlQueryItem {
                channel: String::from(channel),
                message: String::from(message)
            }
        )
    }

    fn parse_title_and_reply_count (&self, document: &NodeRef,  url: &str) -> Result<(String, String), &'static str> {

        return match document.select(".repliers tr") {
            Ok(mut trs) => {
                return match trs.next()  {
                    Some(repliers_tr) => {

                        let repliers_header_option = repliers_tr.as_node().select(".repliers_header").ok().map_or(None, |x| x.last() );

                        if repliers_header_option.is_none() {
                            return Err("fail to build title and reply_count, reason: 'repliers_header' not found");
                        }

                        let repliers_header = repliers_header_option.unwrap();

                        let divs_option = repliers_header.as_node().select("div").ok().map_or(None, |x| Some(x.collect::<Vec<_>>()));

                        if divs_option.is_none() {
                            return Err("fail to build title and reply_count, reason: 'divs' not found");
                        }

                        let divs = divs_option.unwrap();

                        let mut divs_enumerator = divs.iter().enumerate();

                        let count = divs_enumerator.clone().count();
                        if  count < 2 {
                            error!("length of topic_data is invalid. length: {}", count);
                            return Err(&"length of topic_data is invalid.");
                        }

                        let title_option = match divs_enumerator.clone().filter(|&(i, _)| i == 0).map(|(i, e)| (i,e)).next() {
                            Some((i, div)) => {
                                info!("{} => {:?}", i, div.text_contents());
                                Some(div.text_contents().trim().to_string())
                            },
                            None => None
                        };

                        let reply_count = match divs_enumerator.clone().filter(|&(i, _)| i == 1).map(|(i, e)| (i,e)).next() {
                            Some((i, div)) => {
                                info!("{} => {:?}", i, div.text_contents());
                                let re = Regex::new(r"^(?P<count>\d+)個回應$").expect("fail to build title and reply_count, reason: invalid regex");
                                let s_trimmed = div.text_contents().trim().to_string();
                                let cap_option = re.captures(&s_trimmed);
                                if cap_option.is_none() {
                                    None
                                } else {
                                    Some(cap_option.unwrap().name("count").unwrap_or("0").to_string())
                                }
                            },
                            None => None
                        };

                        if  title_option.is_none() || reply_count.is_none() {
                            return Err(&"fail to build title and reply_count, reason: 'topic_data' not found");
                        }

                        Ok(
                            (
                                title_option.unwrap().to_string(),
                                reply_count.unwrap().to_string()
                            )
                        )
                    },
                    None => Err(&"fail to build title and reply_count, reason: 'repliers_tr' not found")
                }
            },
            Err(e) =>  Err("fail to build title and reply_count, reason: 'repliers_tr' not found")
        };

    }

    fn parse_show_reply_items(&self, document: &NodeRef) -> Result<Vec<ShowReplyItem>, &'static str>  {

        let replies_data_option = document.select(".repliers tr[userid][username]").ok().map_or(None, |x| Some(x.collect::<Vec<_>>()) );

        if replies_data_option.is_none() {
            return Err(&"fail to parse show reply items, reason: 'replies_data' not found");
        }

        let replies_data = replies_data_option.unwrap();

        let show_replies = replies_data.iter().enumerate().map(reply_items_handler).collect::<Vec<_>>();

        let err_show_reply_option = show_replies.iter().filter(|x| x.is_err()).next();

        if err_show_reply_option.is_some() {
            return Err(&"fail to parse show reply items, reason: 'error show reply item' was found");
        }

        let result = show_replies.iter().map(|x| x.clone().unwrap() ).collect::<Vec<_>>();

        Ok(result)
    }
}

fn reply_items_handler((index,tr): (usize, &::kuchiki::NodeDataRef<::kuchiki::ElementData>)) -> Result<ShowReplyItem, &'static str> {
    let tr_attrs = (&tr.attributes).borrow();
    let userid_option = tr_attrs.get("userid");

    if userid_option.is_none() {
        return Err("fail to parse show reply item, reason: 'userid' not found");
    }

    let userid = userid_option.unwrap();

    let username_option = tr_attrs.get("username");

    if username_option.is_none() {
        return Err("fail to parse show reply item, reason: 'userame' not found");
    }

    let username = username_option.unwrap();

    let content_elm_option = tr.as_node().select(".repliers_right .ContentGrid").ok().map_or(None, |mut x| x.next());

    if content_elm_option.is_none() {
        return Err("fail to parse show reply item, reason: 'content_elm' not found");
    }
    let content_elm = content_elm_option.unwrap();

    let mut buff = Cursor::new(Vec::new());
    let serialize_result = content_elm.as_node().serialize(&mut buff);
    let vec = buff.into_inner();
    let content_result = String::from_utf8(vec);

    if content_result.is_err() {
        return Err("fail to parse show reply item, reason: 'content' invalid");
    }

    let content = content_result.unwrap();

    let datatime_option = tr.as_node().select(".repliers_right span").ok()
                    .map_or(None, |mut x| x.last() )
                    .map_or(None, |mut x| Some(x.text_contents()));

    if datatime_option.is_none() {
        return Err("fail to parse show reply item, reason: 'datatime' not found");
    }

    let datatime = datatime_option.unwrap();

    let mut vec: Vec<NodeType> = Vec::new();

    vec = recursive(content_elm.as_node());

    Ok(
        ShowReplyItem {
            userid: String::from(userid),
            username: String::from(username),
            content: String::from(content),
            body: vec,
            published_at: String::from(datatime),
        }
    )
}

fn recursive(elm: &NodeRef) -> Vec<NodeType> {

    let mut vec: Vec<NodeType> = Vec::new();

    for (index, child) in elm.children().enumerate() {
        // println!("[{}] => {:?}", index, child);
        let node_data = child.data().clone();

        match node_data {
            NodeData::Element(element_data) => {
                // println!("[{}] => [ELEMENT] => {:?}", index, element_data);
                // println!("[{}] => [ELEMENT] => {:?}", index, child);

                if element_data.name.local.trim().eq("blockquote") {

                    // println!("[{}] => [ELEMENT] => {:?}", index, child.children());
                    let subvec = recursive(&child);
                    let node = NodeType::BlockQuote(BlockQuoteNode { data: subvec });
                    vec.push(node);
                } else if element_data.name.local.trim().eq("br") {
                    let node = NodeType::Br(BrNode {});
                    vec.push(node);
                } else if element_data.name.local.trim().eq("img") {

                    let attrs = (&element_data.attributes).borrow();
                    let url = attrs.get("src").unwrap_or("");
                    let alt = attrs.get("alt").unwrap_or("");
                    let node = NodeType::Image(ImageNode { data: url.to_string(), alt: alt.to_string() });
                    vec.push(node);

                } else {
                    // println!("[{}] => [ELEMENT] => {:?}", index, child);
                    let mut subvec = recursive(&child);
                    vec.append(&mut subvec);
                }
            }
            NodeData::Text(rc) => {
                // println!("[{}] => [TEXT] => {:?}", index, rc);
                let d = rc.clone();
                let b = d.borrow();

                let s = b.trim().to_string();

                if s == "\n" {
                    // s = "\\n".to_string()
                    continue;
                }

                let node = NodeType::Text(TextNode { data: s });
                vec.push(node);
            }
            _ => {}
        }
    }
    vec
}
<|endoftext|>


<commit_before>#![doc(hidden)]

macro_rules! int_module {
    ($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]););
    ($T:ident, #[$attr:meta]) => (
        #[doc = concat!(
            "The smallest value that can be represented by this integer type. Use ",
            "[`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN)",
            "intead.",
        )]
        ///
        /// # Examples
        ///
        /// ```rust
        /// // deprecated way
        #[doc = concat!("let min = std::", stringify!($T), "::MIN;")]
        ///
        /// // intended way
        #[doc = concat!("let min = ", stringify!($T), "::MIN;")]
        /// ```
        ///
        #[$attr]
        pub const MIN: $T = $T::MIN;

        #[doc = concat!(
            "The largest value that can be represented by this integer type. Use ",
            "[`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX)",
            "instead.",
        )]
        ///
        /// # Examples
        ///
        /// ```rust
        /// // deprecated way
        #[doc = concat!("let max = std::", stringify!($T), "::MAX;")]
        ///
        /// // intended way
        #[doc = concat!("let max = ", stringify!($T), "::MAX;")]
        /// ```
        ///
        #[$attr]
        pub const MAX: $T = $T::MAX;
    )
}
<commit_msg>Fix typos.<commit_after>#![doc(hidden)]

macro_rules! int_module {
    ($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]););
    ($T:ident, #[$attr:meta]) => (
        #[doc = concat!(
            "The smallest value that can be represented by this integer type. Use ",
            "[`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN)",
            " instead.",
        )]
        ///
        /// # Examples
        ///
        /// ```rust
        /// // deprecated way
        #[doc = concat!("let min = std::", stringify!($T), "::MIN;")]
        ///
        /// // intended way
        #[doc = concat!("let min = ", stringify!($T), "::MIN;")]
        /// ```
        ///
        #[$attr]
        pub const MIN: $T = $T::MIN;

        #[doc = concat!(
            "The largest value that can be represented by this integer type. Use ",
            "[`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX)",
            " instead.",
        )]
        ///
        /// # Examples
        ///
        /// ```rust
        /// // deprecated way
        #[doc = concat!("let max = std::", stringify!($T), "::MAX;")]
        ///
        /// // intended way
        #[doc = concat!("let max = ", stringify!($T), "::MAX;")]
        /// ```
        ///
        #[$attr]
        pub const MAX: $T = $T::MAX;
    )
}
<|endoftext|>


<commit_before>extern crate luthor;

use std::rc::Rc;
use std::cell::RefCell;
use std::old_io::{File, Open, Read, Write};
use std::old_io::IoError;
use std::old_io::IoResult;
use super::GapBuffer;
use super::gap_buffer;
use super::Position;
use super::Range;
use super::Cursor;
use super::type_detection;
use self::luthor::token::{Token, Category};
use self::luthor::lexers;

/// A UTF-8 buffer with bounds-checked cursor management and persistence.
pub struct Buffer {
    data: Rc<RefCell<GapBuffer>>,
    lexer: Option<fn(&str) -> Vec<Token>>,
    pub path: Option<Path>,
    pub cursor: Cursor,
}

impl Buffer {
    /// Returns the contents of the buffer as a string.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn data(&self) -> String {
        self.data.borrow().to_string()
    }

    /// Writes the contents of the buffer to its path.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::old_io::{File, Open, Read};
    ///
    /// // Set up a buffer and point it to a path.
    /// let mut buffer = scribe::buffer::new();
    /// let write_path = Path::new("my_doc");
    /// buffer.path = Some(write_path.clone());
    ///
    /// // Put some data into the buffer and save it.
    /// buffer.insert("scribe");
    /// buffer.save();
    ///
    /// # let saved_data = File::open_mode(&write_path, Open, Read)
    /// #   .unwrap().read_to_string().unwrap();
    /// # assert_eq!(saved_data, "scribe");
    ///
    /// # std::old_io::fs::unlink(&write_path);
    /// ```
    pub fn save(&self) -> Option<IoError> {
        let path = match self.path.clone() {
            Some(p) => p,
            None => Path::new(""),
        };

        // Try to open and write to the file, returning any errors encountered.
        let mut file = match File::open_mode(&path, Open, Write) {
            Ok(f) => f,
            Err(error) => return Some(error),
        };

        // We use to_string here because we don't want to write the gap contents.
        match file.write(self.data().to_string().as_bytes()) {
            Ok(_) => (),
            Err(error) => return Some(error),
        }

        return None
    }

    /// Inserts `data` into the buffer at the cursor position.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn insert(&mut self, data: &str) {
        self.data.borrow_mut().insert(data, &self.cursor);
    }

    /// Deletes a character at the cursor position. If at the end
    /// of the current line, it'll try to delete a newline character
    /// (joining the lines), succeeding if there's a line below.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// buffer.delete();
    /// assert_eq!(buffer.data(), "cribe");
    /// ```
    pub fn delete(&mut self) {
        // We need to specify a range to delete, so start at
        // the current offset and delete the character to the right.
        let mut end = Position{ line: self.cursor.line, offset: self.cursor.offset + 1 };

        // If there isn't a character to the right,
        // delete the newline by jumping to the start
        // of the next line. If it doesn't exist, that's okay;
        // these values are bounds-checked by delete() anyway.
        if !self.data.borrow().in_bounds(&end) {
            end.line += 1;
            end.offset = 0;
        }

        self.data.borrow_mut().delete(&Range{ start: *self.cursor, end: end});
    }

    /// Produces a set of tokens based on the buffer data
    /// suitable for colorized display, using a lexer for the
    /// buffer data's language and/or format. If a lexer is not
    /// available, the set will consist of a single text-category token.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    ///
    /// // Build the buffer data string back by combining its token lexemes.
    /// let mut data = String::new();
    /// for token in buffer.tokens().iter() {
    ///     data.push_str(token.lexeme.as_slice());
    /// }
    /// assert_eq!(data, "scribe");
    /// ```
    pub fn tokens(&self) -> Vec<Token> {
        match self.lexer {
            Some(lexer) => lexer(&self.data()),
            None => vec![Token{ lexeme: self.data(), category: Category::Text }],
        }
    }
}

/// Creates a new empty buffer. The buffer's cursor is set to the beginning of the buffer.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::new();
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn new() -> Buffer {
    let data = Rc::new(RefCell::new(gap_buffer::new(String::new())));
    let cursor = Cursor{ data: data.clone(), position: Position{ line: 0, offset: 0 }};

    Buffer{ data: data.clone(), path: None, cursor: cursor, lexer: None }
}

/// Creates a new buffer by reading the UTF-8 interpreted file contents of the specified path.
/// The buffer's cursor is set to the beginning of the buffer. The buffer data's type will be
/// inferred based on its extension, and an appropriate lexer will be used, if available (see
/// tokens method for further information on why this happens).
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::from_file(&Path::new("tests/sample/file")).unwrap();
/// assert_eq!(buffer.data(), "it works!\n");
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn from_file(path: &Path) -> IoResult<Buffer> {
    // Try to open and read the file, returning any errors encountered.
    let mut file = match File::open_mode(path, Open, Read) {
        Ok(f) => f,
        Err(error) => return Err(error),
    };
    let mut data = match file.read_to_string() {
        Ok(d) => d,
        Err(error) => return Err(error),
    };

    let data = Rc::new(RefCell::new(gap_buffer::new(data)));
    let cursor = Cursor{ data: data.clone(), position: Position{ line: 0, offset: 0 }};

    // Detect the file type and use its corresponding lexer, if available.
    let lexer = match type_detection::from_path(path) {
        Some(type_detection::Type::JSON) => Some(lexers::json::lex as fn(&str) -> Vec<Token>),
        Some(type_detection::Type::XML) => Some(lexers::xml::lex as fn(&str) -> Vec<Token>),
        _ => None,
    };

    // Create a new buffer using the loaded data, path, and other defaults.
    Ok(Buffer{ data: data.clone(), path: Some(path.clone()), cursor: cursor, lexer: lexer })
}

#[cfg(test)]
mod tests {
    use super::new;
    use super::luthor::token::{Token, Category};

    fn placeholder_lexer(_: &str) -> Vec<Token> {
        vec![Token{ lexeme: "lexer".to_string(), category: Category::Text }]
    }

    #[test]
    fn tokens_returns_one_text_token_when_no_lexer_is_set() {
        let mut buffer = new();
        buffer.insert("scribe");
        let expected_tokens = vec![Token{ lexeme: "scribe".to_string(), category: Category::Text }];
        assert_eq!(buffer.tokens(), expected_tokens);
    }

    #[test]
    fn tokens_returns_result_of_lexer_when_set() {
        let mut buffer = new();
        let expected_tokens = placeholder_lexer("scribe");
        buffer.lexer = Some(placeholder_lexer);
        assert_eq!(buffer.tokens(), expected_tokens);
    }

    #[test]
    fn delete_joins_lines_when_invoked_at_end_of_line() {
        let mut buffer = new();
        buffer.insert("scribe\n library");
        buffer.cursor.move_to_end_of_line();
        buffer.delete();
        assert_eq!(buffer.data(), "scribe library");
    }

    #[test]
    fn delete_does_nothing_when_invoked_at_the_end_of_the_document() {
        let mut buffer = new();
        buffer.insert("scribe\n library");
        buffer.cursor.move_down();
        buffer.cursor.move_to_end_of_line();
        buffer.delete();
        assert_eq!(buffer.data(), "scribe\n library");
    }
}
<commit_msg>Update buffer from_file constructor to take ownership of path arg.<commit_after>extern crate luthor;

use std::rc::Rc;
use std::cell::RefCell;
use std::old_io::{File, Open, Read, Write};
use std::old_io::IoError;
use std::old_io::IoResult;
use super::GapBuffer;
use super::gap_buffer;
use super::Position;
use super::Range;
use super::Cursor;
use super::type_detection;
use self::luthor::token::{Token, Category};
use self::luthor::lexers;

/// A UTF-8 buffer with bounds-checked cursor management and persistence.
pub struct Buffer {
    data: Rc<RefCell<GapBuffer>>,
    lexer: Option<fn(&str) -> Vec<Token>>,
    pub path: Option<Path>,
    pub cursor: Cursor,
}

impl Buffer {
    /// Returns the contents of the buffer as a string.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn data(&self) -> String {
        self.data.borrow().to_string()
    }

    /// Writes the contents of the buffer to its path.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::old_io::{File, Open, Read};
    ///
    /// // Set up a buffer and point it to a path.
    /// let mut buffer = scribe::buffer::new();
    /// let write_path = Path::new("my_doc");
    /// buffer.path = Some(write_path.clone());
    ///
    /// // Put some data into the buffer and save it.
    /// buffer.insert("scribe");
    /// buffer.save();
    ///
    /// # let saved_data = File::open_mode(&write_path, Open, Read)
    /// #   .unwrap().read_to_string().unwrap();
    /// # assert_eq!(saved_data, "scribe");
    ///
    /// # std::old_io::fs::unlink(&write_path);
    /// ```
    pub fn save(&self) -> Option<IoError> {
        let path = match self.path.clone() {
            Some(p) => p,
            None => Path::new(""),
        };

        // Try to open and write to the file, returning any errors encountered.
        let mut file = match File::open_mode(&path, Open, Write) {
            Ok(f) => f,
            Err(error) => return Some(error),
        };

        // We use to_string here because we don't want to write the gap contents.
        match file.write(self.data().to_string().as_bytes()) {
            Ok(_) => (),
            Err(error) => return Some(error),
        }

        return None
    }

    /// Inserts `data` into the buffer at the cursor position.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn insert(&mut self, data: &str) {
        self.data.borrow_mut().insert(data, &self.cursor);
    }

    /// Deletes a character at the cursor position. If at the end
    /// of the current line, it'll try to delete a newline character
    /// (joining the lines), succeeding if there's a line below.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// buffer.delete();
    /// assert_eq!(buffer.data(), "cribe");
    /// ```
    pub fn delete(&mut self) {
        // We need to specify a range to delete, so start at
        // the current offset and delete the character to the right.
        let mut end = Position{ line: self.cursor.line, offset: self.cursor.offset + 1 };

        // If there isn't a character to the right,
        // delete the newline by jumping to the start
        // of the next line. If it doesn't exist, that's okay;
        // these values are bounds-checked by delete() anyway.
        if !self.data.borrow().in_bounds(&end) {
            end.line += 1;
            end.offset = 0;
        }

        self.data.borrow_mut().delete(&Range{ start: *self.cursor, end: end});
    }

    /// Produces a set of tokens based on the buffer data
    /// suitable for colorized display, using a lexer for the
    /// buffer data's language and/or format. If a lexer is not
    /// available, the set will consist of a single text-category token.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    ///
    /// // Build the buffer data string back by combining its token lexemes.
    /// let mut data = String::new();
    /// for token in buffer.tokens().iter() {
    ///     data.push_str(token.lexeme.as_slice());
    /// }
    /// assert_eq!(data, "scribe");
    /// ```
    pub fn tokens(&self) -> Vec<Token> {
        match self.lexer {
            Some(lexer) => lexer(&self.data()),
            None => vec![Token{ lexeme: self.data(), category: Category::Text }],
        }
    }
}

/// Creates a new empty buffer. The buffer's cursor is set to the beginning of the buffer.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::new();
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn new() -> Buffer {
    let data = Rc::new(RefCell::new(gap_buffer::new(String::new())));
    let cursor = Cursor{ data: data.clone(), position: Position{ line: 0, offset: 0 }};

    Buffer{ data: data.clone(), path: None, cursor: cursor, lexer: None }
}

/// Creates a new buffer by reading the UTF-8 interpreted file contents of the specified path.
/// The buffer's cursor is set to the beginning of the buffer. The buffer data's type will be
/// inferred based on its extension, and an appropriate lexer will be used, if available (see
/// tokens method for further information on why this happens).
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::from_file(Path::new("tests/sample/file")).unwrap();
/// assert_eq!(buffer.data(), "it works!\n");
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn from_file(path: Path) -> IoResult<Buffer> {
    // Try to open and read the file, returning any errors encountered.
    let mut file = match File::open_mode(&path, Open, Read) {
        Ok(f) => f,
        Err(error) => return Err(error),
    };
    let mut data = match file.read_to_string() {
        Ok(d) => d,
        Err(error) => return Err(error),
    };

    let data = Rc::new(RefCell::new(gap_buffer::new(data)));
    let cursor = Cursor{ data: data.clone(), position: Position{ line: 0, offset: 0 }};

    // Detect the file type and use its corresponding lexer, if available.
    let lexer = match type_detection::from_path(&path) {
        Some(type_detection::Type::JSON) => Some(lexers::json::lex as fn(&str) -> Vec<Token>),
        Some(type_detection::Type::XML) => Some(lexers::xml::lex as fn(&str) -> Vec<Token>),
        _ => None,
    };

    // Create a new buffer using the loaded data, path, and other defaults.
    Ok(Buffer{ data: data.clone(), path: Some(path), cursor: cursor, lexer: lexer })
}

#[cfg(test)]
mod tests {
    use super::new;
    use super::luthor::token::{Token, Category};

    fn placeholder_lexer(_: &str) -> Vec<Token> {
        vec![Token{ lexeme: "lexer".to_string(), category: Category::Text }]
    }

    #[test]
    fn tokens_returns_one_text_token_when_no_lexer_is_set() {
        let mut buffer = new();
        buffer.insert("scribe");
        let expected_tokens = vec![Token{ lexeme: "scribe".to_string(), category: Category::Text }];
        assert_eq!(buffer.tokens(), expected_tokens);
    }

    #[test]
    fn tokens_returns_result_of_lexer_when_set() {
        let mut buffer = new();
        let expected_tokens = placeholder_lexer("scribe");
        buffer.lexer = Some(placeholder_lexer);
        assert_eq!(buffer.tokens(), expected_tokens);
    }

    #[test]
    fn delete_joins_lines_when_invoked_at_end_of_line() {
        let mut buffer = new();
        buffer.insert("scribe\n library");
        buffer.cursor.move_to_end_of_line();
        buffer.delete();
        assert_eq!(buffer.data(), "scribe library");
    }

    #[test]
    fn delete_does_nothing_when_invoked_at_the_end_of_the_document() {
        let mut buffer = new();
        buffer.insert("scribe\n library");
        buffer.cursor.move_down();
        buffer.cursor.move_to_end_of_line();
        buffer.delete();
        assert_eq!(buffer.data(), "scribe\n library");
    }
}
<|endoftext|>


<commit_before>extern crate sdl2;

use self::sdl2::video::Window;
use self::sdl2::render::Canvas;
use self::sdl2::rect::Rect;
use self::sdl2::pixels::Color;

const DISPLAY_WIDTH: usize = 64;
const DISPLAY_HEIGHT: usize = 32;
const DISPLAY_SCALE: u32 = 8;

pub struct Display {
	frame_buffer: [u8; DISPLAY_WIDTH * DISPLAY_HEIGHT],
	canvas: Canvas<Window>
}

impl Display {
	pub fn new(sdl_context: &sdl2::Sdl) -> Display {
		let video_subsystem = sdl_context.video().unwrap();
		let window = video_subsystem.window("chip8dynarec", DISPLAY_WIDTH as u32 * DISPLAY_SCALE, DISPLAY_HEIGHT as u32 * DISPLAY_SCALE)
    								.position_centered()
    								.opengl()
    								.build()
    								.unwrap();

		Display {
			frame_buffer: [0; DISPLAY_WIDTH * DISPLAY_HEIGHT],
			canvas: window.into_canvas().build().unwrap()
		}
	}

	pub extern "stdcall" fn clear(&mut self) {
		for y in 0..DISPLAY_HEIGHT {
			for x in 0..DISPLAY_WIDTH {
				self.frame_buffer[y * DISPLAY_WIDTH + x] = 0;
			}
		}
	}

	pub extern "stdcall" fn draw_sprite(&mut self, x_position: u8, mut y_position: u8, sprite: &[u8]) -> bool {
		let mut pixel_erased = false;
		y_position %= DISPLAY_HEIGHT as u8;

		for byte in sprite {
			for i in 0..8 {
				let offset = y_position as usize * DISPLAY_WIDTH + (x_position as usize + i) % DISPLAY_WIDTH;
				let old_pixel = self.frame_buffer[offset];

				self.frame_buffer[offset] ^= (byte >> (7 - i)) & 1;

				if old_pixel == 1 && self.frame_buffer[offset] == 0 {
					pixel_erased = true;
				}
			}

			y_position = (y_position + 1) % DISPLAY_HEIGHT as u8;
		}

		pixel_erased
	}

	pub fn refresh(&mut self) {
		self.canvas.set_draw_color(Color::RGB(0x3F, 0x51, 0xB5));
		self.canvas.clear();
		self.canvas.set_draw_color(Color::RGB(0xC5, 0xCA, 0xE9));

		for y in 0..DISPLAY_HEIGHT {
			for x in 0..DISPLAY_WIDTH {
				if self.frame_buffer[y * DISPLAY_WIDTH + x] == 1 {
					let pixel = Rect::new((x * DISPLAY_SCALE as usize) as i32, (y * DISPLAY_SCALE as usize) as i32, DISPLAY_SCALE, DISPLAY_SCALE);
					let _ = self.canvas.fill_rect(pixel);
				}
			}
		}

		self.canvas.present();
	}
}
<commit_msg>Change colors<commit_after>extern crate sdl2;

use self::sdl2::video::Window;
use self::sdl2::render::Canvas;
use self::sdl2::rect::Rect;
use self::sdl2::pixels::Color;

const DISPLAY_WIDTH: usize = 64;
const DISPLAY_HEIGHT: usize = 32;
const DISPLAY_SCALE: u32 = 8;

pub struct Display {
	frame_buffer: [u8; DISPLAY_WIDTH * DISPLAY_HEIGHT],
	canvas: Canvas<Window>
}

impl Display {
	pub fn new(sdl_context: &sdl2::Sdl) -> Display {
		let video_subsystem = sdl_context.video().unwrap();
		let window = video_subsystem.window("chip8dynarec", DISPLAY_WIDTH as u32 * DISPLAY_SCALE, DISPLAY_HEIGHT as u32 * DISPLAY_SCALE)
    								.position_centered()
    								.opengl()
    								.build()
    								.unwrap();

		Display {
			frame_buffer: [0; DISPLAY_WIDTH * DISPLAY_HEIGHT],
			canvas: window.into_canvas().build().unwrap()
		}
	}

	pub extern "stdcall" fn clear(&mut self) {
		for y in 0..DISPLAY_HEIGHT {
			for x in 0..DISPLAY_WIDTH {
				self.frame_buffer[y * DISPLAY_WIDTH + x] = 0;
			}
		}
	}

	pub extern "stdcall" fn draw_sprite(&mut self, x_position: u8, mut y_position: u8, sprite: &[u8]) -> bool {
		let mut pixel_erased = false;
		y_position %= DISPLAY_HEIGHT as u8;

		for byte in sprite {
			for i in 0..8 {
				let offset = y_position as usize * DISPLAY_WIDTH + (x_position as usize + i) % DISPLAY_WIDTH;
				let old_pixel = self.frame_buffer[offset];

				self.frame_buffer[offset] ^= (byte >> (7 - i)) & 1;

				if old_pixel == 1 && self.frame_buffer[offset] == 0 {
					pixel_erased = true;
				}
			}

			y_position = (y_position + 1) % DISPLAY_HEIGHT as u8;
		}

		pixel_erased
	}

	pub fn refresh(&mut self) {
		self.canvas.set_draw_color(Color::RGB(0x00, 0x00, 0x00));
		self.canvas.clear();
		self.canvas.set_draw_color(Color::RGB(0xFF, 0xFF, 0xFF));

		for y in 0..DISPLAY_HEIGHT {
			for x in 0..DISPLAY_WIDTH {
				if self.frame_buffer[y * DISPLAY_WIDTH + x] == 1 {
					let pixel = Rect::new((x * DISPLAY_SCALE as usize) as i32, (y * DISPLAY_SCALE as usize) as i32, DISPLAY_SCALE, DISPLAY_SCALE);
					let _ = self.canvas.fill_rect(pixel);
				}
			}
		}

		self.canvas.present();
	}
}
<|endoftext|>


<commit_before>use std::cell::RefCell;

use proc_macro2::{Delimiter, Span};

use buffer::Cursor;
use error::{self, Error};
use span::IntoSpans;
use token::Token;

/// Support for checking the next token in a stream to decide how to parse.
///
/// An important advantage over [`ParseStream::peek`] is that here we
/// automatically construct an appropriate error message based on the token
/// alternatives that get peeked. If you are producing your own error message,
/// go ahead and use `ParseStream::peek` instead.
///
/// Use [`ParseStream::lookahead1`] to construct this object.
///
/// [`ParseStream::peek`]: struct.ParseBuffer.html#method.peek
/// [`ParseStream::lookahead1`]: struct.ParseBuffer.html#method.lookahead1
pub struct Lookahead1<'a> {
    scope: Span,
    cursor: Cursor<'a>,
    comparisons: RefCell<Vec<String>>,
}

pub fn new(scope: Span, cursor: Cursor) -> Lookahead1 {
    Lookahead1 {
        scope: scope,
        cursor: cursor,
        comparisons: RefCell::new(Vec::new()),
    }
}

impl<'a> Lookahead1<'a> {
    pub fn peek<T: Peek>(&self, token: T) -> bool {
        let _ = token;
        if T::Token::peek(self) {
            return true;
        }
        self.comparisons.borrow_mut().push(T::Token::display());
        false
    }

    pub fn error(self) -> Error {
        let comparisons = self.comparisons.borrow();
        match comparisons.len() {
            0 => if self.cursor.eof() {
                Error::new(self.scope, "unexpected end of input")
            } else {
                Error::new(self.cursor.span(), "unexpected token")
            },
            1 => {
                let message = format!("expected {}", comparisons[0]);
                error::new_at(self.scope, self.cursor, message)
            }
            _ => {
                let join = comparisons.join(", ");
                let message = format!("expected one of: {}", join);
                error::new_at(self.scope, self.cursor, message)
            }
        }
    }

    pub fn cursor(&self) -> Cursor<'a> {
        self.cursor
    }
}

/// Types that can be parsed by looking at just one token.
///
/// Use [`ParseStream::peek`] to peek one of these types in a parse stream
/// without consuming it from the stream.
///
/// This trait is sealed and cannot be implemented for types outside of Syn.
///
/// [`ParseStream::peek`]: struct.ParseBuffer.html#method.peek
pub trait Peek: private::Sealed {
    // Not public API.
    #[doc(hidden)]
    type Token: Token;
}

impl<F: FnOnce(TokenMarker) -> T, T: Token> Peek for F {
    type Token = T;
}

pub enum TokenMarker {}

impl<S> IntoSpans<S> for TokenMarker {
    fn into_spans(self) -> S {
        match self {}
    }
}

pub fn is_delimiter(lookahead: &Lookahead1, delimiter: Delimiter) -> bool {
    lookahead.cursor.group(delimiter).is_some()
}

mod private {
    use super::{Token, TokenMarker};
    pub trait Sealed {}
    impl<F: FnOnce(TokenMarker) -> T, T: Token> Sealed for F {}
}
<commit_msg>Add Lookahead1 example<commit_after>use std::cell::RefCell;

use proc_macro2::{Delimiter, Span};

use buffer::Cursor;
use error::{self, Error};
use span::IntoSpans;
use token::Token;

/// Support for checking the next token in a stream to decide how to parse.
///
/// An important advantage over [`ParseStream::peek`] is that here we
/// automatically construct an appropriate error message based on the token
/// alternatives that get peeked. If you are producing your own error message,
/// go ahead and use `ParseStream::peek` instead.
///
/// Use [`ParseStream::lookahead1`] to construct this object.
///
/// [`ParseStream::peek`]: struct.ParseBuffer.html#method.peek
/// [`ParseStream::lookahead1`]: struct.ParseBuffer.html#method.lookahead1
///
/// # Example
///
/// ```
/// # extern crate syn;
/// #
/// use syn::{ConstParam, Ident, Lifetime, LifetimeDef, Token, TypeParam};
/// use syn::parse::{Parse, ParseStream, Result};
///
/// // A generic parameter, a single one of the comma-separated elements inside
/// // angle brackets in:
/// //
/// //     fn f<T: Clone, 'a, 'b: 'a, const N: usize>() { ... }
/// //
/// // On invalid input, lookahead gives us a reasonable error message.
/// //
/// //     error: expected one of: identifier, lifetime, `const`
/// //       |
/// //     5 |     fn f<!Sized>() {}
/// //       |          ^
/// enum GenericParam {
///     Type(TypeParam),
///     Lifetime(LifetimeDef),
///     Const(ConstParam),
/// }
///
/// impl Parse for GenericParam {
///     fn parse(input: ParseStream) -> Result<Self> {
///         let lookahead = input.lookahead1();
///         if lookahead.peek(Ident) {
///             input.parse().map(GenericParam::Type)
///         } else if lookahead.peek(Lifetime) {
///             input.parse().map(GenericParam::Lifetime)
///         } else if lookahead.peek(Token![const]) {
///             input.parse().map(GenericParam::Const)
///         } else {
///             Err(lookahead.error())
///         }
///     }
/// }
/// #
/// # fn main() {}
/// ```
pub struct Lookahead1<'a> {
    scope: Span,
    cursor: Cursor<'a>,
    comparisons: RefCell<Vec<String>>,
}

pub fn new(scope: Span, cursor: Cursor) -> Lookahead1 {
    Lookahead1 {
        scope: scope,
        cursor: cursor,
        comparisons: RefCell::new(Vec::new()),
    }
}

impl<'a> Lookahead1<'a> {
    pub fn peek<T: Peek>(&self, token: T) -> bool {
        let _ = token;
        if T::Token::peek(self) {
            return true;
        }
        self.comparisons.borrow_mut().push(T::Token::display());
        false
    }

    pub fn error(self) -> Error {
        let comparisons = self.comparisons.borrow();
        match comparisons.len() {
            0 => if self.cursor.eof() {
                Error::new(self.scope, "unexpected end of input")
            } else {
                Error::new(self.cursor.span(), "unexpected token")
            },
            1 => {
                let message = format!("expected {}", comparisons[0]);
                error::new_at(self.scope, self.cursor, message)
            }
            _ => {
                let join = comparisons.join(", ");
                let message = format!("expected one of: {}", join);
                error::new_at(self.scope, self.cursor, message)
            }
        }
    }

    pub fn cursor(&self) -> Cursor<'a> {
        self.cursor
    }
}

/// Types that can be parsed by looking at just one token.
///
/// Use [`ParseStream::peek`] to peek one of these types in a parse stream
/// without consuming it from the stream.
///
/// This trait is sealed and cannot be implemented for types outside of Syn.
///
/// [`ParseStream::peek`]: struct.ParseBuffer.html#method.peek
pub trait Peek: private::Sealed {
    // Not public API.
    #[doc(hidden)]
    type Token: Token;
}

impl<F: FnOnce(TokenMarker) -> T, T: Token> Peek for F {
    type Token = T;
}

pub enum TokenMarker {}

impl<S> IntoSpans<S> for TokenMarker {
    fn into_spans(self) -> S {
        match self {}
    }
}

pub fn is_delimiter(lookahead: &Lookahead1, delimiter: Delimiter) -> bool {
    lookahead.cursor.group(delimiter).is_some()
}

mod private {
    use super::{Token, TokenMarker};
    pub trait Sealed {}
    impl<F: FnOnce(TokenMarker) -> T, T: Token> Sealed for F {}
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
extern crate rustc_serialize;

macro_rules! rpc {
    ($server:ident: $($fn_name:ident($in_:ty) -> $out:ty;)* ) => {
        mod $server {
            use rustc_serialize::json;
            use std::net::{TcpListener, TcpStream};
            use std::thread;
            use std::io::{self, Read, Write};

            pub trait Service: Clone + Send {
                $(
                    fn $fn_name(&self, $in_) -> $out;
                )*

                fn handle_request(self, mut conn: TcpStream) -> Result<(), io::Error> {
                    let mut s = String::new();
                    try!(conn.read_to_string(&mut s));
                    let request: Request = json::decode(&s).unwrap();
                    let response = match request {
                        $(
                            Request::$fn_name(in_) => {
                                Response::$fn_name(self.$fn_name(in_))
                            }
                        )*
                    };
                    conn.write_all(json::encode(&response).unwrap().as_bytes())
                }
            }

            #[allow(non_camel_case_types)]
            #[derive(RustcEncodable, RustcDecodable)]
            enum Request {
                $(
                    $fn_name($in_),
                )*
            }

            #[allow(non_camel_case_types)]
            #[derive(RustcEncodable, RustcDecodable)]
            enum Response {
                $(
                    $fn_name($out),
                )*
            }

            pub struct Server<S: 'static + Service>(S);

            impl<S: Service> Server<S> {
                pub fn new(service: S) -> Server<S> {
                    Server(service)
                }

                pub fn serve(&self, listener: TcpListener) -> io::Error {
                    for conn in listener.incoming() {
                        let conn = match conn {
                            Err(err) => return err,
                            Ok(c) => c,
                        };
                        let service = self.0.clone();
                        thread::spawn(move || {
                            if let Err(err) = service.handle_request(conn) {
                                println!("error handling connection: {:?}", err);
                            }
                        });
                    }
                    unreachable!()
                }
            }
        }
    }
}

rpc!(my_server:
    hello(String) -> ();
    add((i32, i32)) -> i32;
);

use my_server::*;

impl Service for () {
    fn hello(&self, s: String) {
        println!("Hello, {}", s);
    }

    fn add(&self, (x, y): (i32, i32)) -> i32 {
        x + y
    }
}

fn main() {
    let server = Server::new(());
}
<commit_msg>Implement client code<commit_after>#![feature(concat_idents)]
extern crate rustc_serialize;
extern crate byteorder;
use std::net::{TcpListener, TcpStream};

macro_rules! rpc {
    ($server:ident: $($fn_name:ident($in_:ty) -> $out:ty;)* ) => {
        mod $server {
            use rustc_serialize::json;
            use std::net::{TcpListener, TcpStream};
            use std::thread;
            use std::io::{self, Read, Write};
            use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};

            pub trait Service: Clone + Send {
                $(
                    fn $fn_name(&self, $in_) -> $out;
                )*

                fn handle_request(self, mut conn: TcpStream) -> Result<(), io::Error> {
                    let len = try!(conn.read_u64::<BigEndian>());
                    let mut buf = vec![0; len as usize];
                    try!(conn.read_exact(&mut buf));
                    let s = String::from_utf8(buf).unwrap();
                    let request: Request = json::decode(&s).unwrap();
                    println!("Received Request: {:?}", request);
                    match request {
                        $(
                            Request::$fn_name(in_) => {
                                println!("Generating resp...");
                                let resp = self.$fn_name(in_);
                                println!("Response: {:?}", resp);
                                let resp = json::encode(&resp).unwrap();
                                try!(conn.write_u64::<BigEndian>(resp.len() as u64));
                                conn.write_all(resp.as_bytes())
                            }
                        )*
                    }
                }
            }

            #[allow(non_camel_case_types)]
            #[derive(Debug, RustcEncodable, RustcDecodable)]
            enum Request {
                $(
                    $fn_name($in_),
                )*
            }

            pub struct Client(pub TcpStream);

            impl Client {
                $(
                    pub fn $fn_name(&mut self, in_: $in_) -> Result<$out, io::Error> {
                        let ref mut conn = self.0;
                        let request = Request::$fn_name(in_);
                        println!("Sending Request: {:?}", request);
                        let request = json::encode(&request).unwrap();
                        try!(conn.write_u64::<BigEndian>(request.len() as u64));
                        try!(conn.write_all(request.as_bytes()));
                        let len = try!(conn.read_u64::<BigEndian>());
                        let mut buf = vec![0; len as usize];
                        try!(conn.read_exact(&mut buf));
                        let s = String::from_utf8(buf).unwrap();
                        Ok(json::decode(&s).unwrap())
                    }
                )*
            }

            pub struct Server<S: 'static + Service>(S);

            impl<S: Service> Server<S> {
                pub fn new(service: S) -> Server<S> {
                    Server(service)
                }

                pub fn serve(&self, listener: TcpListener) -> io::Error {
                    for conn in listener.incoming() {
                        let conn = match conn {
                            Err(err) => return err,
                            Ok(c) => c,
                        };
                        let service = self.0.clone();
                        thread::spawn(move || {
                            if let Err(err) = service.handle_request(conn) {
                                println!("error handling connection: {:?}", err);
                            }
                        });
                    }
                    unreachable!()
                }
            }
        }
    }
}

rpc!(my_server:
    hello(String) -> ();
    add((i32, i32)) -> i32;
);

use my_server::*;

impl Service for () {
    fn hello(&self, s: String) {
        println!("Hello, {}", s);
    }

    fn add(&self, (x, y): (i32, i32)) -> i32 {
        x + y
    }
}

fn main() {
    println!("Starting");
    let listener = TcpListener::bind("127.0.0.1:9000").unwrap();
    std::thread::spawn(|| {
        let server = Server::new(());
        println!("Server running");
        server.serve(listener);
    });
    let mut client = Client(TcpStream::connect("127.0.0.1:9000").unwrap());
    println!("Client running");
    println!("{}", client.add((1, 2)).unwrap());
}
<|endoftext|>


<commit_before>use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use physics::{Dimensions, Position};
use cgmath::{Matrix4, Point3, Vector3, SquareMatrix};
use specs;
use gfx_app::graphics::{load_texture};
use genmesh::{Vertices, Triangulate};
use genmesh::generators::{Plane, SharedVertex, IndexedPolygon};
use character::gfx_macros::{pipe, CharacterData, VertexData, CharacterSheetSettings, CharacterPosition};
use data;

pub mod gfx_macros;

const SHADER_VERT: &'static [u8] = include_bytes!("character.v.glsl");
const SHADER_FRAG: &'static [u8] = include_bytes!("character.f.glsl");

impl CharacterData {
  pub fn new_empty() -> CharacterData {
    CharacterData { data: [32.0, 32.0, 0.0, 0.0] }
  }

  pub fn new(data: [f32; 4]) -> CharacterData {
    CharacterData { data: data }
  }
}

#[derive(Debug, Clone)]
pub struct Drawable {
  locals: CharacterPosition,
}

impl Drawable {
  pub fn new() -> Drawable {
    Drawable {
      locals: CharacterPosition {
        transform: Matrix4::identity().into()
      },
    }
  }

  pub fn update(&mut self, world_to_clip: &Matrix4<f32>, pos: &Position) {
    self.locals.transform = (world_to_clip * pos.model_to_world()).into();
  }
}

impl specs::Component for Drawable {
  type Storage = specs::VecStorage<Drawable>;
}

pub struct DrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, pipe::Data<R>>,
  data: Vec<CharacterData>,
}

impl<R: gfx::Resources> DrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> DrawSystem<R>
    where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;
    let width = 32;
    let height = 32;

    let tilesheet_bytes = &include_bytes!("../../assets/character.png")[..];
    let plane = Plane::subdivide(width, width);
    let vertex_data: Vec<VertexData> =
      vec![VertexData {
        pos: [0.0, 0.0, 0.0],
        buf_pos: [0.0, 0.0]
      }];

    let index_data: Vec<u32> = plane.indexed_polygon_iter()
      .triangulate()
      .vertices()
      .map(|i| i as u32)
      .collect();

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, &index_data[..]);

    let tile_texture = load_texture(factory, tilesheet_bytes).unwrap();

    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              pipe::new())
      .unwrap();

    let pipeline_data = pipe::Data {
      vbuf: vertex_buf,
      character: factory.create_constant_buffer(512),
      character_cb: factory.create_constant_buffer(1),
      charactersheet: (tile_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    DrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data: data::load_character(),
    }
  }
}
<commit_msg>Add draw function for character<commit_after>use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use physics::{Dimensions, Position};
use cgmath::{Matrix4, Point3, Vector3, SquareMatrix, Deg, Point2};
use specs;
use gfx_app::graphics::load_texture;
use genmesh::{Vertices, Triangulate};
use genmesh::generators::{Plane, SharedVertex, IndexedPolygon};
use character::gfx_macros::{pipe, CharacterData, VertexData, CharacterSheetSettings, CharacterPosition};
use data;

pub mod gfx_macros;

const SHADER_VERT: &'static [u8] = include_bytes!("character.v.glsl");
const SHADER_FRAG: &'static [u8] = include_bytes!("character.f.glsl");

impl CharacterData {
  pub fn new_empty() -> CharacterData {
    CharacterData { data: [32.0, 32.0, 0.0, 0.0] }
  }

  pub fn new(data: [f32; 4]) -> CharacterData {
    CharacterData { data: data }
  }
}

#[derive(Debug, Clone)]
pub struct Drawable {
  locals: CharacterPosition,
}

impl Drawable {
  pub fn new() -> Drawable {
    Drawable {
      locals: CharacterPosition {
        transform: Matrix4::identity().into()
      },
    }
  }

  pub fn update(&mut self, world_to_clip: &Matrix4<f32>) {
    self.locals.transform = (*world_to_clip).into();
  }
}

impl specs::Component for Drawable {
  type Storage = specs::VecStorage<Drawable>;
}

pub struct DrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, pipe::Data<R>>,
  data: Vec<CharacterData>,
}

impl<R: gfx::Resources> DrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> DrawSystem<R>
    where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;
    let width = 32;
    let height = 32;

    let tilesheet_bytes = &include_bytes!("../../assets/character.png")[..];
    let plane = Plane::subdivide(width, width);
    let vertex_data: Vec<VertexData> =
      vec![VertexData {
        pos: [0.0, 0.0, 0.0],
        buf_pos: [0.0, 0.0]
      }];

    let index_data: Vec<u32> = plane.indexed_polygon_iter()
      .triangulate()
      .vertices()
      .map(|i| i as u32)
      .collect();

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, &index_data[..]);

    let tile_texture = load_texture(factory, tilesheet_bytes).unwrap();

    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              pipe::new())
      .unwrap();

    let pipeline_data = pipe::Data {
      vbuf: vertex_buf,
      character: factory.create_constant_buffer(512),
      character_cb: factory.create_constant_buffer(1),
      charactersheet: (tile_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    DrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data: data::load_character(),
    }
  }

  pub fn draw<C>(&mut self,
                 drawable: Drawable,
                 encoder: &mut gfx::Encoder<R, C>)
    where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.locals, &drawable.locals);
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<C> specs::System<C> for PreDrawSystem {
  fn run(&mut self, arg: specs::RunArg, _: C) {
    use specs::Join;
    let (mut character, dim) =
      arg.fetch(|w| (
        w.write::<Drawable>(),
        w.read_resource::<Dimensions>()));

    for c in (&mut character).join() {
      let world_to_clip = dim.world_to_clip();
      c.update(&world_to_clip);
    }
  }
}
<|endoftext|>


<commit_before>mod page;
pub use self::page::Page;

use std::env;
use std::io::Read;
use std::time::Duration;
use std::default::Default;
use std::collections::BTreeMap;

use url::Url;
use mime;
use reqwest::Client as HttpClient;
use reqwest::header::{ContentType, UserAgent};
use reqwest::StatusCode;
use reqwest::Response as HttpResponse;
use robotparser::RobotFileParser;
use html5ever::tokenizer::Tokenizer;
use html5ever::tokenizer::BufferQueue;
use sidekiq::Client as SidekiqClient;
use sidekiq::ClientOpts as SidekiqClientOpts;
use sidekiq::RedisPool;
use encoding::{DecoderTrap, Encoding};
use encoding::all::UTF_8;
use url_serde::Serde;

const MAMAN_ENV: &str = "MAMAN_ENV";
const MAMAN_ENV_DEFAULT: &str = "development";

pub struct Spider<'a> {
    pub base_url: Url,
    pub visited_urls: Vec<Serde<Url>>,
    pub unvisited_urls: Vec<Serde<Url>>,
    pub env: String,
    pub limit: isize,
    pub mime_types: Vec<mime::Mime>,
    sidekiq: SidekiqClient,
    robot_parser: RobotFileParser<'a>,
}

impl<'a> Spider<'a> {
    pub fn new(
        redis_pool: RedisPool,
        base_url: Url,
        limit: isize,
        mime_types: Vec<mime::Mime>,
    ) -> Spider<'a> {
        let maman_env =
            env::var(&MAMAN_ENV.to_owned()).unwrap_or_else(|_| MAMAN_ENV_DEFAULT.to_owned());
        let robots_txt = base_url.join("/robots.txt").unwrap();
        let robot_file_parser = RobotFileParser::new(robots_txt);
        let client_opts = SidekiqClientOpts {
            namespace: Some(maman_env.to_string()),
        };
        let sidekiq = SidekiqClient::new(redis_pool, client_opts);
        Spider {
            base_url,
            visited_urls: Vec::new(),
            unvisited_urls: Vec::new(),
            sidekiq,
            env: maman_env,
            robot_parser: robot_file_parser,
            limit,
            mime_types,
        }
    }

    #[allow(unknown_lints, needless_pass_by_value)]
    pub fn visit_page(&mut self, page: Page) {
        self.visited_urls.push(page.url.clone());
        for u in &page.urls {
            self.unvisited_urls.push(u.clone());
        }
        if let Err(err) = self.sidekiq.push(page.to_job()) {
            error!("SidekiqClient push failed: {}", err);
        }
    }

    pub fn crawl(&mut self) {
        self.robot_parser.read();
        let base_url = self.base_url.clone();
        if let Some(response) = Spider::load_url(self.base_url.as_ref(), &self.mime_types) {
            self.visit(&base_url, response);
            while let Some(url) = self.unvisited_urls.pop() {
                if self.continue_to_crawl() {
                    if !self.visited_urls.contains(&url) {
                        if let Some(response) = Spider::load_url(url.as_ref(), &self.mime_types) {
                            self.visit(&url, response);
                        }
                    }
                } else {
                    break;
                }
            }
        }
    }

    pub fn read_page(page: Page, document: &str) -> Tokenizer<Page> {
        let mut tok = Tokenizer::new(page, Default::default());
        let mut input = BufferQueue::new();
        input.push_back(String::from(document).into());
        let _ = tok.feed(&mut input);
        tok.end();
        tok
    }

    fn visit(&mut self, page_url: &Url, response: HttpResponse) {
        if self.can_visit(page_url) {
            info!("{}", page_url);
            if let Some(page) = Spider::read_response(page_url, response) {
                self.visit_page(page);
            }
        }
    }

    fn continue_to_crawl(&self) -> bool {
        self.limit == 0 || (self.visited_urls.len() as isize) < self.limit
    }

    fn can_visit(&self, page_url: &Url) -> bool {
        self.robot_parser.can_fetch(maman_name!(), page_url.path())
    }

    fn read_response(page_url: &Url, mut response: HttpResponse) -> Option<Page> {
        let mut headers = BTreeMap::new();
        {
            for h in response.headers().iter() {
                headers.insert(h.name().to_ascii_lowercase(), h.value_string());
            }
        }
        let mut document = vec![];
        let _ = response.read_to_end(&mut document);
        match UTF_8.decode(&document, DecoderTrap::Ignore) {
            Ok(doc) => {
                let page = Page::new(
                    page_url.clone(),
                    doc.to_string(),
                    headers.clone(),
                    response.status().to_string(),
                );
                let read = Spider::read_page(page, &doc);
                Some(read.sink)
            }
            Err(_) => None,
        }
    }

    fn load_url(url: &str, mime_types: &[mime::Mime]) -> Option<HttpResponse> {
        let client = HttpClient::builder()
            .timeout(Duration::from_secs(5))
            .build()
            .expect("HttpClient failed to construct");
        match client
            .get(url)
            .header(UserAgent::new(maman_user_agent!().to_owned()))
            .send()
        {
            Err(_) => None,
            Ok(response) => match response.status() {
                StatusCode::Ok | StatusCode::NotModified => {
                    if mime_types.is_empty()
                        || mime_types.contains(response.headers().get::<ContentType>().unwrap())
                    {
                        Some(response)
                    } else {
                        None
                    }
                }
                _ => None,
            },
        }
    }
}
<commit_msg>Fix mime type filter when charset is present<commit_after>mod page;
pub use self::page::Page;

use std::env;
use std::io::Read;
use std::time::Duration;
use std::default::Default;
use std::collections::BTreeMap;

use url::Url;
use mime;
use reqwest::Client as HttpClient;
use reqwest::header::{ContentType, UserAgent};
use reqwest::StatusCode;
use reqwest::Response as HttpResponse;
use robotparser::RobotFileParser;
use html5ever::tokenizer::Tokenizer;
use html5ever::tokenizer::BufferQueue;
use sidekiq::Client as SidekiqClient;
use sidekiq::ClientOpts as SidekiqClientOpts;
use sidekiq::RedisPool;
use encoding::{DecoderTrap, Encoding};
use encoding::all::UTF_8;
use url_serde::Serde;

const MAMAN_ENV: &str = "MAMAN_ENV";
const MAMAN_ENV_DEFAULT: &str = "development";

pub struct Spider<'a> {
    pub base_url: Url,
    pub visited_urls: Vec<Serde<Url>>,
    pub unvisited_urls: Vec<Serde<Url>>,
    pub env: String,
    pub limit: isize,
    pub mime_types: Vec<mime::Mime>,
    sidekiq: SidekiqClient,
    robot_parser: RobotFileParser<'a>,
}

impl<'a> Spider<'a> {
    pub fn new(
        redis_pool: RedisPool,
        base_url: Url,
        limit: isize,
        mime_types: Vec<mime::Mime>,
    ) -> Spider<'a> {
        let maman_env =
            env::var(&MAMAN_ENV.to_owned()).unwrap_or_else(|_| MAMAN_ENV_DEFAULT.to_owned());
        let robots_txt = base_url.join("/robots.txt").unwrap();
        let robot_file_parser = RobotFileParser::new(robots_txt);
        let client_opts = SidekiqClientOpts {
            namespace: Some(maman_env.to_string()),
        };
        let sidekiq = SidekiqClient::new(redis_pool, client_opts);
        Spider {
            base_url,
            visited_urls: Vec::new(),
            unvisited_urls: Vec::new(),
            sidekiq,
            env: maman_env,
            robot_parser: robot_file_parser,
            limit,
            mime_types,
        }
    }

    #[allow(unknown_lints, needless_pass_by_value)]
    pub fn visit_page(&mut self, page: Page) {
        self.visited_urls.push(page.url.clone());
        for u in &page.urls {
            self.unvisited_urls.push(u.clone());
        }
        if let Err(err) = self.sidekiq.push(page.to_job()) {
            error!("SidekiqClient push failed: {}", err);
        }
    }

    pub fn crawl(&mut self) {
        self.robot_parser.read();
        let base_url = self.base_url.clone();
        if let Some(response) = Spider::load_url(self.base_url.as_ref(), &self.mime_types) {
            self.visit(&base_url, response);
            while let Some(url) = self.unvisited_urls.pop() {
                if self.continue_to_crawl() {
                    if !self.visited_urls.contains(&url) {
                        if let Some(response) = Spider::load_url(url.as_ref(), &self.mime_types) {
                            self.visit(&url, response);
                        }
                    }
                } else {
                    break;
                }
            }
        }
    }

    pub fn read_page(page: Page, document: &str) -> Tokenizer<Page> {
        let mut tok = Tokenizer::new(page, Default::default());
        let mut input = BufferQueue::new();
        input.push_back(String::from(document).into());
        let _ = tok.feed(&mut input);
        tok.end();
        tok
    }

    fn visit(&mut self, page_url: &Url, response: HttpResponse) {
        if self.can_visit(page_url) {
            info!("{}", page_url);
            if let Some(page) = Spider::read_response(page_url, response) {
                self.visit_page(page);
            }
        }
    }

    fn continue_to_crawl(&self) -> bool {
        self.limit == 0 || (self.visited_urls.len() as isize) < self.limit
    }

    fn can_visit(&self, page_url: &Url) -> bool {
        self.robot_parser.can_fetch(maman_name!(), page_url.path())
    }

    fn read_response(page_url: &Url, mut response: HttpResponse) -> Option<Page> {
        let mut headers = BTreeMap::new();
        {
            for h in response.headers().iter() {
                headers.insert(h.name().to_ascii_lowercase(), h.value_string());
            }
        }
        let mut document = vec![];
        let _ = response.read_to_end(&mut document);
        match UTF_8.decode(&document, DecoderTrap::Ignore) {
            Ok(doc) => {
                let page = Page::new(
                    page_url.clone(),
                    doc.to_string(),
                    headers.clone(),
                    response.status().to_string(),
                );
                let read = Spider::read_page(page, &doc);
                Some(read.sink)
            }
            Err(_) => None,
        }
    }

    fn load_url(url: &str, mime_types: &[mime::Mime]) -> Option<HttpResponse> {
        let client = HttpClient::builder()
            .timeout(Duration::from_secs(5))
            .build()
            .expect("HttpClient failed to construct");
        match client
            .get(url)
            .header(UserAgent::new(maman_user_agent!().to_owned()))
            .send()
        {
            Err(_) => None,
            Ok(response) => match response.status() {
                StatusCode::Ok | StatusCode::NotModified => {
                    if mime_types.is_empty() {
                        Some(response)
                    } else {
                        match response.headers().clone().get::<ContentType>() {
                            Some(mime_type) => {
                                let mime_str_without_charset =
                                    match (mime_type.type_(), mime_type.subtype()) {
                                        (type_, subtype) => {
                                            let mut text = type_.to_string();
                                            text.push_str("/");
                                            text.push_str(subtype.as_ref());
                                            text
                                        }
                                    };
                                let mime_without_charset: mime::Mime =
                                    mime_str_without_charset.parse().unwrap();
                                if mime_types.contains(&mime_without_charset) {
                                    Some(response)
                                } else {
                                    None
                                }
                            }
                            None => None,
                        }
                    }
                }
                _ => None,
            },
        }
    }
}
<|endoftext|>


<commit_before>import std._str.rustrt.sbuf;
import std._vec.rustrt.vbuf;

type Bool = int;

native mod llvm = "libLLVM-2.7.so" {

  type ModuleRef;
  type ContextRef;
  type TypeRef;
  type TypeHandleRef;
  type ValueRef;
  type BasicBlockRef;
  type BuilderRef;
  type ModuleProviderRef;
  type MemoryBufferRef;
  type PassManagerRef;
  type UseRef;

  fn ModuleCreateWithName(sbuf ModuleID) -> ModuleRef;
  fn DisposeModule(ModuleRef M);

  fn GetDataLayout(ModuleRef M) -> sbuf;
  fn SetDataLayout(ModuleRef M, sbuf Triple);

  fn GetTarget(ModuleRef M) -> sbuf;
  fn SetTarget(ModuleRef M, sbuf Triple);

  fn AddTypeName(ModuleRef M, sbuf Name, TypeRef Ty) -> Bool;
  fn DeleteTypeName(ModuleRef M, sbuf Name);
  fn GetTypeByName(ModuleRef M, sbuf Name) -> TypeRef;

  fn DumpModule(ModuleRef M);

  fn GetTypeContext(TypeRef Ty) -> ContextRef;

  fn Int1TypeInContext(ContextRef C) -> TypeRef;
  fn Int8TypeInContext(ContextRef C) -> TypeRef;
  fn Int16TypeInContext(ContextRef C) -> TypeRef;
  fn Int32TypeInContext(ContextRef C) -> TypeRef;
  fn Int64TypeInContext(ContextRef C) -> TypeRef;
  fn IntTypeInContext(ContextRef C, uint NumBits) -> TypeRef;

  fn Int1Type() -> TypeRef;
  fn Int8Type() -> TypeRef;
  fn Int16Type() -> TypeRef;
  fn Int32Type() -> TypeRef;
  fn Int64Type() -> TypeRef;
  fn IntType(uint NumBits) -> TypeRef;
  fn GetIntTypeWidth(TypeRef IntegerTy) -> uint;

  fn FloatTypeInContext(ContextRef C) -> TypeRef;
  fn DoubleTypeInContext(ContextRef C) -> TypeRef;
  fn X86FP80TypeInContext(ContextRef C) -> TypeRef;
  fn FP128TypeInContext(ContextRef C) -> TypeRef;
  fn PPCFP128TypeInContext(ContextRef C) -> TypeRef;

  fn FloatType() -> TypeRef;
  fn DoubleType() -> TypeRef;
  fn X86FP80Type() -> TypeRef;
  fn FP128Type() -> TypeRef;
  fn PPCFP128Type() -> TypeRef;

  fn FunctionType(TypeRef ReturnType, vbuf ParamTypes,
                  uint ParamCount, Bool IsVarArg) -> TypeRef;
  fn IsFunctionVarArg(TypeRef FunctionTy) -> Bool;
  fn GetReturnType(TypeRef FunctionTy) -> TypeRef;
  fn CountParamTypes(TypeRef FunctionTy) -> uint;
  fn GetParamTypes(TypeRef FunctionTy, vbuf Dest);

  fn StructTypeInContext(ContextRef C, vbuf ElementTypes,
                         uint ElementCount, Bool Packed) -> TypeRef;
  fn StructType(vbuf ElementTypes, uint ElementCount,
                Bool Packed) -> TypeRef;
  fn CountStructElementTypes(TypeRef StructTy) -> uint;
  fn GetStructElementTypes(TypeRef StructTy, vbuf Dest);
  fn IsPackedStruct(TypeRef StructTy) -> Bool;

  fn UnionTypeInContext(ContextRef C, vbuf ElementTypes,
                        uint ElementCount) -> TypeRef;
  fn UnionType(vbuf ElementTypes, uint ElementCount) -> TypeRef;
  fn CountUnionElementTypes(TypeRef UnionTy) -> uint;
  fn GetUnionElementTypes(TypeRef UnionTy, vbuf Dest);

  fn ArrayType(TypeRef ElementType, uint ElementCount) -> TypeRef;
  fn PointerType(TypeRef ElementType, uint AddressSpace) -> TypeRef;
  fn VectorType(TypeRef ElementType, uint ElementCount) -> TypeRef;

  fn GetElementType(TypeRef Ty) -> TypeRef;
  fn GetArrayLength(TypeRef ArrayTy) -> uint;
  fn GetPointerAddressSpace(TypeRef PointerTy) -> uint;
  fn GetVectorSize(TypeRef VectorTy) -> uint;

  fn VoidTypeInContext(ContextRef C) -> TypeRef;
  fn LabelTypeInContext(ContextRef C) -> TypeRef;
  fn OpaqueTypeInContext(ContextRef C) -> TypeRef;

  fn VoidType() -> TypeRef;
  fn LabelType() -> TypeRef;
  fn OpaqueType() -> TypeRef;

  fn CreateTypeHandle(TypeRef PotentiallyAbstractTy) -> TypeHandleRef;
  fn RefineType(TypeRef AbstractTy, TypeRef ConcreteTy);
  fn ResolveTypeHandle(TypeHandleRef TypeHandle) -> TypeRef;
  fn DisposeTypeHandle(TypeHandleRef TypeHandle);

  fn TypeOf(ValueRef Val) -> TypeRef;
  fn GetValueName(ValueRef Val) -> sbuf;
  fn SetValueName(ValueRef Val, sbuf Name);
  fn DumpValue(ValueRef Val);
  fn ReplaceAllUsesWith(ValueRef OldVal, ValueRef NewVal);
  fn HasMetadata(ValueRef Val) -> int;
  fn GetMetadata(ValueRef Val, uint KindID) -> ValueRef;
  fn SetMetadata(ValueRef Val, uint KindID, ValueRef Node);

}<commit_msg>Add another pile of LLVM bindings.<commit_after>import std._str.rustrt.sbuf;
import std._vec.rustrt.vbuf;

type ULongLong = u64;
type LongLong = i64;
type Long = i32;
type Bool = int;

native mod llvm = "libLLVM-2.7.so" {

  type ModuleRef;
  type ContextRef;
  type TypeRef;
  type TypeHandleRef;
  type ValueRef;
  type BasicBlockRef;
  type BuilderRef;
  type ModuleProviderRef;
  type MemoryBufferRef;
  type PassManagerRef;
  type UseRef;

  /* Create and destroy contexts. */
  fn ContextCreate() -> ContextRef;
  fn GetGlobalContext() -> ContextRef;
  fn ContextDispose(ContextRef C);
  fn GetMDKindIDInContext(ContextRef C, sbuf Name, uint SLen) -> uint;
  fn GetMDKindID(sbuf Name, uint SLen) -> uint;

  /* Create and destroy modules. */
  fn ModuleCreateWithName(sbuf ModuleID) -> ModuleRef;
  fn DisposeModule(ModuleRef M);

  /** Data layout. See Module::getDataLayout. */
  fn GetDataLayout(ModuleRef M) -> sbuf;
  fn SetDataLayout(ModuleRef M, sbuf Triple);

  /** Target triple. See Module::getTargetTriple. */
  fn GetTarget(ModuleRef M) -> sbuf;
  fn SetTarget(ModuleRef M, sbuf Triple);

  /** See Module::addTypeName. */
  fn AddTypeName(ModuleRef M, sbuf Name, TypeRef Ty) -> Bool;
  fn DeleteTypeName(ModuleRef M, sbuf Name);
  fn GetTypeByName(ModuleRef M, sbuf Name) -> TypeRef;

  /** See Module::dump. */
  fn DumpModule(ModuleRef M);

  /** See Module::setModuleInlineAsm. */
  fn SetModuleInlineAsm(ModuleRef M, sbuf Asm);

  /** See llvm::LLVMType::getContext. */
  fn GetTypeContext(TypeRef Ty) -> ContextRef;

  /* Operations on integer types */
  fn Int1TypeInContext(ContextRef C) -> TypeRef;
  fn Int8TypeInContext(ContextRef C) -> TypeRef;
  fn Int16TypeInContext(ContextRef C) -> TypeRef;
  fn Int32TypeInContext(ContextRef C) -> TypeRef;
  fn Int64TypeInContext(ContextRef C) -> TypeRef;
  fn IntTypeInContext(ContextRef C, uint NumBits) -> TypeRef;

  fn Int1Type() -> TypeRef;
  fn Int8Type() -> TypeRef;
  fn Int16Type() -> TypeRef;
  fn Int32Type() -> TypeRef;
  fn Int64Type() -> TypeRef;
  fn IntType(uint NumBits) -> TypeRef;
  fn GetIntTypeWidth(TypeRef IntegerTy) -> uint;

  /* Operations on real types */
  fn FloatTypeInContext(ContextRef C) -> TypeRef;
  fn DoubleTypeInContext(ContextRef C) -> TypeRef;
  fn X86FP80TypeInContext(ContextRef C) -> TypeRef;
  fn FP128TypeInContext(ContextRef C) -> TypeRef;
  fn PPCFP128TypeInContext(ContextRef C) -> TypeRef;

  fn FloatType() -> TypeRef;
  fn DoubleType() -> TypeRef;
  fn X86FP80Type() -> TypeRef;
  fn FP128Type() -> TypeRef;
  fn PPCFP128Type() -> TypeRef;

  /* Operations on function types */
  fn FunctionType(TypeRef ReturnType, vbuf ParamTypes,
                  uint ParamCount, Bool IsVarArg) -> TypeRef;
  fn IsFunctionVarArg(TypeRef FunctionTy) -> Bool;
  fn GetReturnType(TypeRef FunctionTy) -> TypeRef;
  fn CountParamTypes(TypeRef FunctionTy) -> uint;
  fn GetParamTypes(TypeRef FunctionTy, vbuf Dest);

  /* Operations on struct types */
  fn StructTypeInContext(ContextRef C, vbuf ElementTypes,
                         uint ElementCount, Bool Packed) -> TypeRef;
  fn StructType(vbuf ElementTypes, uint ElementCount,
                Bool Packed) -> TypeRef;
  fn CountStructElementTypes(TypeRef StructTy) -> uint;
  fn GetStructElementTypes(TypeRef StructTy, vbuf Dest);
  fn IsPackedStruct(TypeRef StructTy) -> Bool;

  /* Operations on union types */
  fn UnionTypeInContext(ContextRef C, vbuf ElementTypes,
                        uint ElementCount) -> TypeRef;
  fn UnionType(vbuf ElementTypes, uint ElementCount) -> TypeRef;
  fn CountUnionElementTypes(TypeRef UnionTy) -> uint;
  fn GetUnionElementTypes(TypeRef UnionTy, vbuf Dest);

  /* Operations on array, pointer, and vector types (sequence types) */
  fn ArrayType(TypeRef ElementType, uint ElementCount) -> TypeRef;
  fn PointerType(TypeRef ElementType, uint AddressSpace) -> TypeRef;
  fn VectorType(TypeRef ElementType, uint ElementCount) -> TypeRef;

  fn GetElementType(TypeRef Ty) -> TypeRef;
  fn GetArrayLength(TypeRef ArrayTy) -> uint;
  fn GetPointerAddressSpace(TypeRef PointerTy) -> uint;
  fn GetVectorSize(TypeRef VectorTy) -> uint;

  /* Operations on other types */
  fn VoidTypeInContext(ContextRef C) -> TypeRef;
  fn LabelTypeInContext(ContextRef C) -> TypeRef;
  fn OpaqueTypeInContext(ContextRef C) -> TypeRef;

  fn VoidType() -> TypeRef;
  fn LabelType() -> TypeRef;
  fn OpaqueType() -> TypeRef;

  /* Operations on type handles */
  fn CreateTypeHandle(TypeRef PotentiallyAbstractTy) -> TypeHandleRef;
  fn RefineType(TypeRef AbstractTy, TypeRef ConcreteTy);
  fn ResolveTypeHandle(TypeHandleRef TypeHandle) -> TypeRef;
  fn DisposeTypeHandle(TypeHandleRef TypeHandle);

  /* Operations on all values */
  fn TypeOf(ValueRef Val) -> TypeRef;
  fn GetValueName(ValueRef Val) -> sbuf;
  fn SetValueName(ValueRef Val, sbuf Name);
  fn DumpValue(ValueRef Val);
  fn ReplaceAllUsesWith(ValueRef OldVal, ValueRef NewVal);
  fn HasMetadata(ValueRef Val) -> int;
  fn GetMetadata(ValueRef Val, uint KindID) -> ValueRef;
  fn SetMetadata(ValueRef Val, uint KindID, ValueRef Node);

  /* Operations on Uses */
  fn GetFirstUse(ValueRef Val) -> UseRef;
  fn GetNextUse(UseRef U) -> UseRef;
  fn GetUser(UseRef U) -> ValueRef;
  fn GetUsedValue(UseRef U) -> ValueRef;

  /* Operations on Users */
  fn GetOperand(ValueRef Val, uint Index) -> ValueRef;

  /* Operations on constants of any type */
  fn ConstNull(TypeRef Ty) -> ValueRef; /* all zeroes */
  fn ConstAllOnes(TypeRef Ty) -> ValueRef; /* only for int/vector */
  fn GetUndef(TypeRef Ty) -> ValueRef;
  fn IsConstant(ValueRef Val) -> Bool;
  fn IsNull(ValueRef Val) -> Bool;
  fn IsUndef(ValueRef Val) -> Bool;
  fn ConstPointerNull(TypeRef Ty) -> ValueRef;

  /* Operations on metadata */
  fn MDStringInContext(ContextRef C, sbuf Str, uint SLen) -> ValueRef;
  fn MDString(sbuf Str, uint SLen) -> ValueRef;
  fn MDNodeInContext(ContextRef C, vbuf Vals, uint Count) -> ValueRef;
  fn MDNode(vbuf Vals, uint Count) -> ValueRef;

  /* Operations on scalar constants */
  fn ConstInt(TypeRef IntTy, ULongLong N, Bool SignExtend) -> ValueRef;
  fn ConstIntOfString(TypeRef IntTy, sbuf Text, u8 Radix) -> ValueRef;
  fn ConstIntOfStringAndSize(TypeRef IntTy, sbuf Text,
                             uint SLen, u8 Radix) -> ValueRef;
  fn ConstReal(TypeRef RealTy, f64 N) -> ValueRef;
  fn ConstRealOfString(TypeRef RealTy, sbuf Text) -> ValueRef;
  fn ConstRealOfStringAndSize(TypeRef RealTy, sbuf Text,
                              uint SLen) -> ValueRef;
  fn ConstIntGetZExtValue(ValueRef ConstantVal) -> ULongLong;
  fn ConstIntGetSExtValue(ValueRef ConstantVal) -> LongLong;

  /* Operations on composite constants */
  fn ConstStringInContext(ContextRef C, sbuf Str,
                          uint Length, Bool DontNullTerminate) -> ValueRef;
  fn ConstStructInContext(ContextRef C, vbuf ConstantVals,
                          uint Count, Bool Packed) -> ValueRef;

  fn ConstString(sbuf Str, uint Length, Bool DontNullTerminate) -> ValueRef;
  fn ConstArray(TypeRef ElementTy,
                vbuf ConstantVals, uint Length) -> ValueRef;
  fn ConstStruct(vbuf ConstantVals, uint Count, Bool Packed) -> ValueRef;
  fn ConstVector(vbuf ScalarConstantVals, uint Size) -> ValueRef;
  fn ConstUnion(TypeRef Ty, ValueRef Val) -> ValueRef;

  /* Constant expressions */
  fn AlignOf(TypeRef Ty) -> ValueRef;
  fn SizeOf(TypeRef Ty) -> ValueRef;
  fn ConstNeg(ValueRef ConstantVal) -> ValueRef;
  fn ConstNSWNeg(ValueRef ConstantVal) -> ValueRef;
  fn ConstNUWNeg(ValueRef ConstantVal) -> ValueRef;
  fn ConstFNeg(ValueRef ConstantVal) -> ValueRef;
  fn ConstNot(ValueRef ConstantVal) -> ValueRef;
  fn ConstAdd(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstNSWAdd(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstNUWAdd(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstFAdd(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstSub(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstNSWSub(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstNUWSub(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstFSub(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstMul(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstNSWMul(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstNUWMul(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstFMul(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstUDiv(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstSDiv(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstExactSDiv(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstFDiv(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstURem(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstSRem(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstFRem(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstAnd(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstOr(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstXor(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstShl(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstLShr(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstAShr(ValueRef LHSConstant, ValueRef RHSConstant) -> ValueRef;
  fn ConstGEP(ValueRef ConstantVal,
              vbuf ConstantIndices, uint NumIndices) -> ValueRef;
  fn ConstInBoundsGEP(ValueRef ConstantVal,
                      vbuf ConstantIndices,
                      uint NumIndices) -> ValueRef;
  fn ConstTrunc(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
  fn ConstSExt(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
  fn ConstZExt(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
  fn ConstFPTrunc(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
  fn ConstFPExt(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
  fn ConstUIToFP(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
  fn ConstSIToFP(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
  fn ConstFPToUI(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
  fn ConstFPToSI(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
  fn ConstPtrToInt(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
  fn ConstIntToPtr(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
  fn ConstBitCast(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
  fn ConstZExtOrBitCast(ValueRef ConstantVal,
                        TypeRef ToType) -> ValueRef;
  fn ConstSExtOrBitCast(ValueRef ConstantVal,
                        TypeRef ToType) -> ValueRef;
  fn ConstTruncOrBitCast(ValueRef ConstantVal,
                         TypeRef ToType) -> ValueRef;
  fn ConstPointerCast(ValueRef ConstantVal,
                      TypeRef ToType) -> ValueRef;
  fn ConstIntCast(ValueRef ConstantVal, TypeRef ToType,
                  Bool isSigned) -> ValueRef;
  fn ConstFPCast(ValueRef ConstantVal, TypeRef ToType) -> ValueRef;
  fn ConstSelect(ValueRef ConstantCondition,
                 ValueRef ConstantIfTrue,
                 ValueRef ConstantIfFalse) -> ValueRef;
  fn ConstExtractElement(ValueRef VectorConstant,
                         ValueRef IndexConstant) -> ValueRef;
  fn ConstInsertElement(ValueRef VectorConstant,
                        ValueRef ElementValueConstant,
                        ValueRef IndexConstant) -> ValueRef;
  fn ConstShuffleVector(ValueRef VectorAConstant,
                        ValueRef VectorBConstant,
                        ValueRef MaskConstant) -> ValueRef;
  fn ConstExtractValue(ValueRef AggConstant, vbuf IdxList,
                       uint NumIdx) -> ValueRef;
  fn ConstInsertValue(ValueRef AggConstant,
                      ValueRef ElementValueConstant,
                      vbuf IdxList, uint NumIdx) -> ValueRef;
  fn ConstInlineAsm(TypeRef Ty,
                    sbuf AsmString, sbuf Constraints,
                    Bool HasSideEffects, Bool IsAlignStack) -> ValueRef;
  fn BlockAddress(ValueRef F, BasicBlockRef BB) -> ValueRef;

}<|endoftext|>