<commit_before>use std::ffi;
use std::fs;
use std::io::{Read, Write};
use std::path;

use itertools;
use liquid;
use regex;
use serde_yaml;

use frontmatter;
use datetime;
use legacy::wildwest;
use jekyll::jk_errors::{ErrorKind, Result};

lazy_static! {
    static ref FRONT_MATTER_DIVIDE: regex::Regex = regex::Regex::new(r"---\s*\r?\n").unwrap();
}

#[derive(Debug, Eq, PartialEq, Default, Clone, Serialize, Deserialize)]
pub struct JkFrontmatterBuilder(liquid::Object);

impl JkFrontmatterBuilder {
    pub fn new() -> JkFrontmatterBuilder {
        JkFrontmatterBuilder(liquid::Object::new())
    }
}

impl From<JkFrontmatterBuilder> for wildwest::FrontmatterBuilder {
    fn from(jk_front: JkFrontmatterBuilder) -> Self {
        // Convert jekyll frontmatter into frontmatter (with `custom`)
        let mut custom_attributes = jk_front.0;
        let front = frontmatter::FrontmatterBuilder::new()
            .merge_slug(custom_attributes
                            .remove("slug")
                            .and_then(|v| v.as_str().map(|s| s.to_owned())))
            .merge_title(custom_attributes
                             .remove("title")
                             .and_then(|v| v.as_str().map(|s| s.to_owned())))
            .merge_description(custom_attributes
                                   .remove("excerpt")
                                   .and_then(|v| v.as_str().map(|s| s.to_owned())))
            .merge_categories(custom_attributes
                                  .remove("categories")
                                  .and_then(|v| {
                                                v.as_array()
                                                    .map(|v| {
                                                             v.iter()
                                                                 .map(|v| v.to_string())
                                                                 .collect()
                                                         })
                                            }))
            .merge_permalink(custom_attributes
                                 .remove("permalink")
                                 .and_then(|v| v.as_str().map(|s| s.to_owned())))
            .merge_draft(custom_attributes
                             .remove("published")
                             .and_then(|v| v.as_bool().map(|b| !b)))
            .merge_layout(custom_attributes
                              .remove("layout")
                              .and_then(|v| v.as_str().map(|s| s.to_owned())))
            .merge_published_date(custom_attributes
                                      .remove("date")
                                      .and_then(|d| {
                                                    d.as_str().and_then(datetime::DateTime::parse)
                                                }))
            .merge_custom(custom_attributes);
        front.into()
    }
}

#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct JkDocument {
    front: wildwest::FrontmatterBuilder,
    content: String,
}

impl JkDocument {
    pub fn parse_string(doc: String) -> Result<JkDocument> {
        let (front, content) = split_document(&doc)?;
        let front: JkFrontmatterBuilder =
            front
                .map(|f| serde_yaml::from_str(f))
                .unwrap_or_else(|| Ok(JkFrontmatterBuilder::default()))?;
        let front: wildwest::FrontmatterBuilder = front.into();

        Ok(JkDocument {
               front: front,
               content: content.to_owned(),
           })
    }

    pub fn parse(source_file: &path::Path) -> Result<JkDocument> {
        let doc: String = read_file(source_file)?;
        JkDocument::parse_string(doc)
    }

    pub fn dump(self) -> Result<String> {
        let front = self.front;
        let front = dump_front(front)?;

        let content = self.content;

        let converted = itertools::join(&[front, "---".to_owned(), content], "\n");
        Ok(converted)
    }
}

fn dump_front(front: wildwest::FrontmatterBuilder) -> Result<String> {
    let mut converted = serde_yaml::to_string(&front)?;
    converted.drain(..4);
    Ok(converted)
}

fn convert_document(source_file: &path::Path, dest_dir: &path::Path) -> Result<()> {
    let doc = JkDocument::parse(source_file)?;
    let converted = doc.dump()?;
    let dest_file = dest_dir.join(source_file.with_extension("md").file_name().unwrap());

    if !dest_dir.exists() {
        fs::create_dir_all(&dest_dir)?;
    }
    let mut dest = fs::File::create(dest_file)?;
    dest.write_all(converted.as_bytes())?;
    Ok(())
}

pub fn convert_from_jk(source: &path::Path, dest: &path::Path) -> Result<()> {
    if dest.is_file() {
        Err(ErrorKind::CantOutputInFile.into())
    } else if source.is_file() {
        convert_document(source, dest)
    } else if source.is_dir() {
        for file in source.read_dir()? {
            if let Ok(file) = file {
                let file_path = file.path();
                let ext = file_path.extension().unwrap_or(ffi::OsStr::new(""));
                if file_path.is_file() {
                    if ext == "md" || ext == "markdown" {
                        convert_document(&file.path(), dest)?
                    } else {
                        warn!("unsupported file extension")
                    }
                } else {
                    warn!("sub directory parsing is not supported yet")
                }
            }
        }
        Ok(())
    } else {
        Err(ErrorKind::InternalError.into())
    }
}

fn read_file<P: AsRef<path::Path>>(path: P) -> Result<String> {
    let mut file = fs::File::open(path.as_ref())?;
    let mut text = String::new();
    file.read_to_string(&mut text)?;
    Ok(text)
}

fn split_document(content: &str) -> Result<(Option<&str>, &str)> {
    if FRONT_MATTER_DIVIDE.is_match(content) {
        let mut splits = FRONT_MATTER_DIVIDE.splitn(content, 3);
        let first = splits.next().unwrap_or("");
        let second = splits.next().unwrap_or("");
        let third = splits.next().unwrap_or("");

        if third.is_empty() {
            // only one "---"
            if first.is_empty() {
                Ok((None, second))
            } else {
                Ok((Some(first), second))
            }
        } else {
            // first should be empty
            if second.is_empty() {
                Ok((None, third))
            } else {
                Ok((Some(second), third))
            }
        }
    } else {
        Ok((None, content))
    }
}

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

    #[test]
    fn split_document_empty_document() {
        let fixture = "";

        let (front, content) = split_document(fixture).unwrap();
        assert!(front.is_none());
        assert_eq!(content, "");
    }

    #[test]
    fn split_document_empty_sections() {
        let fixture = "---\n---\n";

        let (front, content) = split_document(fixture).unwrap();
        assert!(front.is_none());
        assert_eq!(content, "");
    }

    #[test]
    fn split_document_content_only() {
        let fixture = "Content\n";

        let (front, content) = split_document(fixture).unwrap();
        assert!(front.is_none());
        assert_eq!(content, "Content\n");
    }

    #[test]
    fn split_document_empty_front() {
        let fixture = "---\n---\nContent\n";

        let (front, content) = split_document(fixture).unwrap();
        assert!(front.is_none());
        assert_eq!(content, "Content\n");
    }

    #[test]
    #[ignore] // TODO(epage): This should pass
    fn split_document_empty_content() {
        let fixture = "---\ntitle: test_post\n---\n";

        let (front, content) = split_document(fixture).unwrap();
        assert_eq!(front.unwrap(), "title: test_post\n");
        assert_eq!(content, "");
    }

    #[test]
    fn split_document_all_sections() {
        let fixture = "---\ntitle: test_post\n---\nContent\n";

        let (front, content) = split_document(fixture).unwrap();
        assert_eq!(front.unwrap(), "title: test_post\n");
        assert_eq!(content, "Content\n");
    }

    #[test]
    fn frontmatter_empty() {
        let front = JkFrontmatterBuilder::default();
        let _front: wildwest::FrontmatterBuilder = front.into();

        // TODO(epage): Confirm jekyll defaults overrode cobalt defaults
    }

    static FIXTURE_FULL: &str = r#"title: test_post
date: 2017-05-03T20:55:07+00:00
layout: post
permalink: /2017/05/03/test_post/
categories:
  - cat1
  - cat2
"#;

    #[test]
    fn frontmatter_full() {
        let front: JkFrontmatterBuilder = serde_yaml::from_str(FIXTURE_FULL).unwrap();
        let front: wildwest::FrontmatterBuilder = front.into();
        let front = dump_front(front).unwrap();
        let front: liquid::Object = serde_yaml::from_str(&front).unwrap();

        let expected: liquid::Object =
            [("path".to_owned(), liquid::Value::str("/2017/05/03/test_post/")),
             ("title".to_owned(), liquid::Value::str("test_post")),
             ("extends".to_owned(), liquid::Value::str("post")),
             ("categories".to_owned(),
              liquid::Value::Array(vec![liquid::Value::str("cat1"), liquid::Value::str("cat2")]))]
                    .iter()
                    .cloned()
                    .collect();
        assert_eq!(front, expected);
    }

    static FIXTURE_CUSTOM: &str = r#"id: 33
title: test_post
author: TheAuthor
guid: http://url.com/?p=33
tags:
  - tag1
  - tag2
  - tag3
"#;

    #[test]
    fn frontmatter_custom() {
        let front: JkFrontmatterBuilder = serde_yaml::from_str(FIXTURE_CUSTOM).unwrap();
        let front: wildwest::FrontmatterBuilder = front.into();
        let front = dump_front(front).unwrap();
        let front: liquid::Object = serde_yaml::from_str(&front).unwrap();

        let expected: liquid::Object = [("id".to_owned(), liquid::Value::Num(33.0f32)),
                                        ("title".to_owned(), liquid::Value::str("test_post")),
                                        ("author".to_owned(), liquid::Value::str("TheAuthor")),
                                        ("guid".to_owned(),
                                         liquid::Value::str("http://url.com/?p=33")),
                                        ("tags".to_owned(),
                                         liquid::Value::Array(vec![liquid::Value::str("tag1"),
                                                                   liquid::Value::str("tag2"),
                                                                   liquid::Value::str("tag3")]))]
                .iter()
                .cloned()
                .collect();
        assert_eq!(front, expected);
    }

    static FIXTURE_MINIMAL: &str = r#"title: test_post"#;
    static EXPECTED_MINIMAL: &str = r#"title: test_post"#;

    #[test]
    fn parse_string_ok() {
        let fixture = format!("---\n{}---\nthe content\n", FIXTURE_MINIMAL);

        let doc = JkDocument::parse_string(fixture).unwrap();
        let actual = doc.dump().unwrap();

        let expected = format!("{}\n---\nthe content\n", EXPECTED_MINIMAL);
        assert_eq!(actual, expected);
    }
}
<commit_msg>fix(jekyll): Make frontmatter parser strict<commit_after>use std::ffi;
use std::fs;
use std::io::{Read, Write};
use std::path;

use itertools;
use liquid;
use regex;
use serde_yaml;

use frontmatter;
use datetime;
use legacy::wildwest;
use jekyll::jk_errors::{ErrorKind, Result};

lazy_static! {
    static ref FRONT_MATTER_DIVIDE: regex::Regex = regex::Regex::new(r"---\s*\r?\n").unwrap();
}

#[derive(Debug, Eq, PartialEq, Default, Clone, Serialize, Deserialize)]
pub struct JkFrontmatterBuilder(liquid::Object);

impl JkFrontmatterBuilder {
    pub fn new() -> JkFrontmatterBuilder {
        JkFrontmatterBuilder(liquid::Object::new())
    }
}

impl From<JkFrontmatterBuilder> for wildwest::FrontmatterBuilder {
    fn from(jk_front: JkFrontmatterBuilder) -> Self {
        // Convert jekyll frontmatter into frontmatter (with `custom`)
        let mut custom_attributes = jk_front.0;
        let front = frontmatter::FrontmatterBuilder::new()
            .merge_slug(custom_attributes
                            .remove("slug")
                            .and_then(|v| v.as_str().map(|s| s.to_owned())))
            .merge_title(custom_attributes
                             .remove("title")
                             .and_then(|v| v.as_str().map(|s| s.to_owned())))
            .merge_description(custom_attributes
                                   .remove("excerpt")
                                   .and_then(|v| v.as_str().map(|s| s.to_owned())))
            .merge_categories(custom_attributes
                                  .remove("categories")
                                  .and_then(|v| {
                                                v.as_array()
                                                    .map(|v| {
                                                             v.iter()
                                                                 .map(|v| v.to_string())
                                                                 .collect()
                                                         })
                                            }))
            .merge_permalink(custom_attributes
                                 .remove("permalink")
                                 .and_then(|v| v.as_str().map(|s| s.to_owned())))
            .merge_draft(custom_attributes
                             .remove("published")
                             .and_then(|v| v.as_bool().map(|b| !b)))
            .merge_layout(custom_attributes
                              .remove("layout")
                              .and_then(|v| v.as_str().map(|s| s.to_owned())))
            .merge_published_date(custom_attributes
                                      .remove("date")
                                      .and_then(|d| {
                                                    d.as_str().and_then(datetime::DateTime::parse)
                                                }))
            .merge_custom(custom_attributes);
        front.into()
    }
}

#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct JkDocument {
    front: wildwest::FrontmatterBuilder,
    content: String,
}

impl JkDocument {
    pub fn parse_string(doc: String) -> Result<JkDocument> {
        let (front, content) = split_document(&doc)?;
        let front: JkFrontmatterBuilder =
            front
                .map(|f| serde_yaml::from_str(f))
                .unwrap_or_else(|| Ok(JkFrontmatterBuilder::default()))?;
        let front: wildwest::FrontmatterBuilder = front.into();

        Ok(JkDocument {
               front: front,
               content: content.to_owned(),
           })
    }

    pub fn parse(source_file: &path::Path) -> Result<JkDocument> {
        let doc: String = read_file(source_file)?;
        JkDocument::parse_string(doc)
    }

    pub fn dump(self) -> Result<String> {
        let front = self.front;
        let front = dump_front(front)?;

        let content = self.content;

        let converted = itertools::join(&[front, "---".to_owned(), content], "\n");
        Ok(converted)
    }
}

fn dump_front(front: wildwest::FrontmatterBuilder) -> Result<String> {
    let mut converted = serde_yaml::to_string(&front)?;
    converted.drain(..4);
    Ok(converted)
}

fn convert_document(source_file: &path::Path, dest_dir: &path::Path) -> Result<()> {
    let doc = JkDocument::parse(source_file)?;
    let converted = doc.dump()?;
    let dest_file = dest_dir.join(source_file.with_extension("md").file_name().unwrap());

    if !dest_dir.exists() {
        fs::create_dir_all(&dest_dir)?;
    }
    let mut dest = fs::File::create(dest_file)?;
    dest.write_all(converted.as_bytes())?;
    Ok(())
}

pub fn convert_from_jk(source: &path::Path, dest: &path::Path) -> Result<()> {
    if dest.is_file() {
        Err(ErrorKind::CantOutputInFile.into())
    } else if source.is_file() {
        convert_document(source, dest)
    } else if source.is_dir() {
        for file in source.read_dir()? {
            if let Ok(file) = file {
                let file_path = file.path();
                let ext = file_path.extension().unwrap_or(ffi::OsStr::new(""));
                if file_path.is_file() {
                    if ext == "md" || ext == "markdown" {
                        convert_document(&file.path(), dest)?
                    } else {
                        warn!("unsupported file extension")
                    }
                } else {
                    warn!("sub directory parsing is not supported yet")
                }
            }
        }
        Ok(())
    } else {
        Err(ErrorKind::InternalError.into())
    }
}

fn read_file<P: AsRef<path::Path>>(path: P) -> Result<String> {
    let mut file = fs::File::open(path.as_ref())?;
    let mut text = String::new();
    file.read_to_string(&mut text)?;
    Ok(text)
}

fn split_document(content: &str) -> Result<(Option<&str>, &str)> {
    if FRONT_MATTER_DIVIDE.is_match(content) {
        let mut splits = FRONT_MATTER_DIVIDE.splitn(content, 3);
        let first = splits.next().unwrap_or("");
        let second = splits.next().unwrap_or("");
        let third = splits.next().unwrap_or("");

        if !first.is_empty() {
            bail!("Invalid leading text in frontmatter: {:?}", first);
        }
        if second.is_empty() {
            Ok((None, third))
        } else {
            Ok((Some(second), third))
        }
    } else {
        Ok((None, content))
    }
}

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

    #[test]
    fn split_document_empty_document() {
        let fixture = "";

        let (front, content) = split_document(fixture).unwrap();
        assert!(front.is_none());
        assert_eq!(content, "");
    }

    #[test]
    fn split_document_empty_sections() {
        let fixture = "---\n---\n";

        let (front, content) = split_document(fixture).unwrap();
        assert!(front.is_none());
        assert_eq!(content, "");
    }

    #[test]
    fn split_document_content_only() {
        let fixture = "Content\n";

        let (front, content) = split_document(fixture).unwrap();
        assert!(front.is_none());
        assert_eq!(content, "Content\n");
    }

    #[test]
    fn split_document_empty_front() {
        let fixture = "---\n---\nContent\n";

        let (front, content) = split_document(fixture).unwrap();
        assert!(front.is_none());
        assert_eq!(content, "Content\n");
    }

    #[test]
    fn split_document_empty_content() {
        let fixture = "---\ntitle: test_post\n---\n";

        let (front, content) = split_document(fixture).unwrap();
        assert_eq!(front.unwrap(), "title: test_post\n");
        assert_eq!(content, "");
    }

    #[test]
    fn split_document_all_sections() {
        let fixture = "---\ntitle: test_post\n---\nContent\n";

        let (front, content) = split_document(fixture).unwrap();
        assert_eq!(front.unwrap(), "title: test_post\n");
        assert_eq!(content, "Content\n");
    }

    #[test]
    fn frontmatter_empty() {
        let front = JkFrontmatterBuilder::default();
        let _front: wildwest::FrontmatterBuilder = front.into();

        // TODO(epage): Confirm jekyll defaults overrode cobalt defaults
    }

    static FIXTURE_FULL: &str = r#"title: test_post
date: 2017-05-03T20:55:07+00:00
layout: post
permalink: /2017/05/03/test_post/
categories:
  - cat1
  - cat2
"#;

    #[test]
    fn frontmatter_full() {
        let front: JkFrontmatterBuilder = serde_yaml::from_str(FIXTURE_FULL).unwrap();
        let front: wildwest::FrontmatterBuilder = front.into();
        let front = dump_front(front).unwrap();
        let front: liquid::Object = serde_yaml::from_str(&front).unwrap();

        let expected: liquid::Object =
            [("path".to_owned(), liquid::Value::str("/2017/05/03/test_post/")),
             ("title".to_owned(), liquid::Value::str("test_post")),
             ("extends".to_owned(), liquid::Value::str("post")),
             ("categories".to_owned(),
              liquid::Value::Array(vec![liquid::Value::str("cat1"), liquid::Value::str("cat2")]))]
                    .iter()
                    .cloned()
                    .collect();
        assert_eq!(front, expected);
    }

    static FIXTURE_CUSTOM: &str = r#"id: 33
title: test_post
author: TheAuthor
guid: http://url.com/?p=33
tags:
  - tag1
  - tag2
  - tag3
"#;

    #[test]
    fn frontmatter_custom() {
        let front: JkFrontmatterBuilder = serde_yaml::from_str(FIXTURE_CUSTOM).unwrap();
        let front: wildwest::FrontmatterBuilder = front.into();
        let front = dump_front(front).unwrap();
        let front: liquid::Object = serde_yaml::from_str(&front).unwrap();

        let expected: liquid::Object = [("id".to_owned(), liquid::Value::Num(33.0f32)),
                                        ("title".to_owned(), liquid::Value::str("test_post")),
                                        ("author".to_owned(), liquid::Value::str("TheAuthor")),
                                        ("guid".to_owned(),
                                         liquid::Value::str("http://url.com/?p=33")),
                                        ("tags".to_owned(),
                                         liquid::Value::Array(vec![liquid::Value::str("tag1"),
                                                                   liquid::Value::str("tag2"),
                                                                   liquid::Value::str("tag3")]))]
                .iter()
                .cloned()
                .collect();
        assert_eq!(front, expected);
    }

    static FIXTURE_MINIMAL: &str = r#"title: test_post"#;
    static EXPECTED_MINIMAL: &str = r#"title: test_post"#;

    #[test]
    fn parse_string_ok() {
        let fixture = format!("---\n{}---\nthe content\n", FIXTURE_MINIMAL);

        let doc = JkDocument::parse_string(fixture).unwrap();
        let actual = doc.dump().unwrap();

        let expected = format!("{}\n---\nthe content\n", EXPECTED_MINIMAL);
        assert_eq!(actual, expected);
    }
}
<|endoftext|>


<commit_before>#![warn(missing_docs)]

use super::*;
use crate::associations::HasTable;
use crate::backend::Backend;
use crate::dsl::{Filter, Select};
use crate::expression::{
    is_aggregate, AppearsOnTable, Expression, SelectableExpression, ValidGrouping,
};
use crate::query_builder::nodes::StaticQueryFragment;
use crate::query_builder::{AsQuery, AstPass, FromClause, QueryFragment, QueryId, SelectStatement};
use crate::query_dsl::join_dsl::InternalJoinDsl;
use crate::query_dsl::methods::*;
use crate::query_dsl::QueryDsl;
use crate::query_source::joins::ToInnerJoin;
use crate::query_source::joins::{
    AppendSelection, Inner, Join, JoinOn, LeftOuter, OnClauseWrapper,
};
use crate::query_source::{AppearsInFromClause, Column, Never, Once, QuerySource, Table};
use crate::result::QueryResult;
use std::marker::PhantomData;

#[derive(Debug, Copy)]
pub struct Alias<T, F>(PhantomData<(T, F)>);

#[derive(Debug)]
pub struct AliasedField<A, F>(A, PhantomData<F>);

pub trait Named {
    const NAME: &'static str;
}

pub trait AliasNotEqualHelper<Table2, Alias1, Alias2> {
    type Count;
}

impl<T, F> Clone for Alias<T, F> {
    fn clone(&self) -> Self {
        Alias::new()
    }
}

impl<T, F, C> Clone for AliasedField<Alias<T, F>, C> {
    fn clone(&self) -> Self {
        AliasedField(self.0.clone(), PhantomData)
    }
}

impl<T, F> QueryId for Alias<T, F> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<T, F> Alias<T, F> {
    pub fn new() -> Self {
        Alias(PhantomData)
    }
}

impl<T, F> Alias<T, F>
where
    T: Table,
{
    pub fn field<C>(&self, _: C) -> AliasedField<Self, C>
    where
        C: Column<Table = T>,
    {
        AliasedField(Alias::new(), PhantomData)
    }
}

impl<QS, T, F, C> AppearsOnTable<QS> for AliasedField<Alias<T, F>, C>
where
    QS: AppearsInFromClause<Alias<T, F>, Count = Once>,
    T: Table,
    C: Column<Table = T>,
{
}

impl<T, F, C> QueryId for AliasedField<Alias<T, F>, C>
where
    T: Table + 'static,
    C: Column<Table = T> + 'static,
    F: 'static,
{
    type QueryId = Self;
    const HAS_STATIC_QUERY_ID: bool = true;
}

#[doc(hidden)]
pub trait FieldAliasMapper<A> {
    type Out;

    fn map(self) -> Self::Out;
}

impl<T, F, C> FieldAliasMapper<Alias<T, F>> for C
where
    C: Column<Table = T>,
    T: Table,
{
    type Out = AliasedField<Alias<T, F>, C>;

    fn map(self) -> Self::Out {
        AliasedField(Alias::new(), PhantomData)
    }
}

macro_rules! field_alias_mapper {
    ($(
        $Tuple:tt {
            $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+
        }
    )+) => {
        $(
            impl<_T, _F, $($T,)*> FieldAliasMapper<Alias<_T, _F>> for ($($T,)*) {
                type Out = ($(AliasedField<Alias<_T, _F>, $T>,)*);

                fn map(self) -> Self::Out {
                    (
                        $(AliasedField(Alias::new(), PhantomData::<$T>),)*
                    )
                }
            }
        )*
    }
}

diesel_derives::__diesel_for_each_tuple!(field_alias_mapper);

impl<T, F> QuerySource for Alias<T, F>
where
    T: Table + QuerySource + HasTable<Table = T>,
    T::DefaultSelection: FieldAliasMapper<Self>,
    <T::DefaultSelection as FieldAliasMapper<Self>>::Out: SelectableExpression<Self>,
{
    type FromClause = Self;
    type DefaultSelection = <T::DefaultSelection as FieldAliasMapper<Self>>::Out;

    fn from_clause(&self) -> Self::FromClause {
        Alias::new()
    }

    fn default_selection(&self) -> Self::DefaultSelection {
        T::default_selection(&T::table()).map()
    }
}

impl<T, F, DB> QueryFragment<DB> for Alias<T, F>
where
    DB: Backend,
    T: Table + StaticQueryFragment,
    T::Component: QueryFragment<DB>,
    F: Named,
{
    fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        T::STATIC_COMPONENT.walk_ast(pass.reborrow())?;
        pass.push_sql(" AS ");
        pass.push_identifier(F::NAME)?;
        Ok(())
    }
}

impl<T, F, C, DB> QueryFragment<DB> for AliasedField<Alias<T, F>, C>
where
    DB: Backend,
    T: Table,
    C: Column<Table = T>,
    F: Named,
{
    fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        pass.push_identifier(F::NAME)?;
        pass.push_sql(".");
        pass.push_identifier(C::NAME)?;
        Ok(())
    }
}

impl<T, F, C> Expression for AliasedField<Alias<T, F>, C>
where
    T: Table,
    C: Column<Table = T> + Expression,
{
    type SqlType = C::SqlType;
}

impl<T, F, C> SelectableExpression<Alias<T, F>> for AliasedField<Alias<T, F>, C>
where
    T: Table,
    C: Column<Table = T>,
    Self: AppearsOnTable<Alias<T, F>>,
{
}

impl<T, F, C> ValidGrouping<()> for AliasedField<Alias<T, F>, C>
where
    T: Table,
    C: Column<Table = T>,
{
    type IsAggregate = is_aggregate::No;
}
impl<T, F, C> ValidGrouping<AliasedField<Alias<T, F>, C>> for AliasedField<Alias<T, F>, C>
where
    T: Table,
    C: Column<Table = T>,
{
    type IsAggregate = is_aggregate::Yes;
}

impl<T, F> AsQuery for Alias<T, F>
where
    T: AsQuery + Table + HasTable<Table = T>,
    Self: QuerySource,
    <Self as QuerySource>::DefaultSelection: ValidGrouping<()>,
{
    type SqlType = <<Self as QuerySource>::DefaultSelection as Expression>::SqlType;
    type Query = SelectStatement<FromClause<Self>>;

    fn as_query(self) -> Self::Query {
        SelectStatement::simple(self)
    }
}

impl<T1, T2, F1, F2> AppearsInFromClause<Alias<T1, F1>> for Alias<T2, F2>
where
    T2: AliasNotEqualHelper<T1, F2, F1>,
{
    type Count = T2::Count;
}

impl<T, F> AppearsInFromClause<Alias<T, F>> for ()
where
    T: Table,
{
    type Count = Never;
}

impl<T, F> QueryDsl for Alias<T, F> where T: Table {}

impl<T, F, Predicate> FilterDsl<Predicate> for Alias<T, F>
where
    T: Table,
    Self: AsQuery,
    <Self as AsQuery>::Query: FilterDsl<Predicate>,
{
    type Output = Filter<<Self as AsQuery>::Query, Predicate>;

    fn filter(self, predicate: Predicate) -> Self::Output {
        self.as_query().filter(predicate)
    }
}

impl<T, F, Selection> SelectDsl<Selection> for Alias<T, F>
where
    Selection: Expression,
    Self: AsQuery,
    T: Table,
    <Self as AsQuery>::Query: SelectDsl<Selection>,
{
    type Output = Select<<Self as AsQuery>::Query, Selection>;

    fn select(self, selection: Selection) -> Self::Output {
        self.as_query().select(selection)
    }
}

#[macro_export]
macro_rules! __internal_alias_helper {
    (
        $left_table: ident as $left_alias: ident,
        $right_table: ident as $right_alias: ident,
        $($table: ident as $alias: ident,)*
    ) => {
        static_cond!{if $left_table == $right_table {
            impl $crate::query_source::AliasNotEqualHelper<$left_table::table, $right_alias, $left_alias> for $right_table::table {
                type Count = $crate::query_source::Never;
            }

            impl $crate::query_source::AliasNotEqualHelper<$right_table::table, $left_alias, $right_alias> for $left_table::table {
                type Count = $crate::query_source::Never;
            }
        }}

        __internal_alias_helper!($left_table as $left_alias, $($table as $alias,)*);
        __internal_alias_helper!($right_alias as $right_alias, $($table as $alias,)*);
    };

    ($table: ident as $alias: ident,) => {}
}

/// TODO
#[macro_export]
macro_rules! alias {
    ($($table: ident as $alias: ident),* $(,)?) => {{
        $(
            #[allow(non_camel_case_types)]
            #[derive(Debug, Clone, Copy)]
            struct $alias;

            impl $crate::query_source::Named for $alias {
                const NAME: &'static str = stringify!($alias);
            }

            impl
                $crate::query_source::AppearsInFromClause<
                $crate::query_source::Alias<$table::table, $alias>,
            > for $table::table
            {
                type Count = $crate::query_source::Never;
            }

            impl $crate::query_source::AppearsInFromClause<$table::table>
                for $crate::query_source::Alias<$table::table, $alias>
            {
                type Count = $crate::query_source::Never;
            }

            impl $crate::query_source::AliasNotEqualHelper<$table::table, $alias, $alias> for $table::table {
                type Count = $crate::query_source::Once;
            }
        )*
        __internal_alias_helper!($($table as $alias,)*);
        ($($crate::query_source::Alias::<$table::table, $alias>::new()),*)
    }};
}

impl<T: Table, F> ToInnerJoin for Alias<T, F> {
    type InnerJoin = Self;
}

impl<T, Rhs, Kind, On, F> InternalJoinDsl<Rhs, Kind, On> for Alias<T, F>
where
    Self: AsQuery,
    <Self as AsQuery>::Query: InternalJoinDsl<Rhs, Kind, On>,
{
    type Output = <<Self as AsQuery>::Query as InternalJoinDsl<Rhs, Kind, On>>::Output;

    fn join(self, rhs: Rhs, kind: Kind, on: On) -> Self::Output {
        self.as_query().join(rhs, kind, on)
    }
}

impl<Left, Right, T, F, C> SelectableExpression<Join<Left, Right, LeftOuter>>
    for AliasedField<Alias<T, F>, C>
where
    Self: AppearsOnTable<Join<Left, Right, LeftOuter>>,
    Self: SelectableExpression<Left>,
    Left: QuerySource,
    Right: AppearsInFromClause<Alias<T, F>, Count = Never> + QuerySource,
{
}

impl<Left, Right, T, F, C> SelectableExpression<Join<Left, Right, Inner>>
    for AliasedField<Alias<T, F>, C>
where
    Self: AppearsOnTable<Join<Left, Right, Inner>>,
    Left: AppearsInFromClause<Alias<T, F>> + QuerySource,
    Right: AppearsInFromClause<Alias<T, F>> + QuerySource,
    (Left::Count, Right::Count): Pick<Left, Right>,
    Self: SelectableExpression<<(Left::Count, Right::Count) as Pick<Left, Right>>::Selection>,
{
}

// FIXME: Remove this when overlapping marker traits are stable
impl<Join, On, T, F, C> SelectableExpression<JoinOn<Join, On>> for AliasedField<Alias<T, F>, C> where
    Self: SelectableExpression<Join> + AppearsOnTable<JoinOn<Join, On>>
{
}

// FIXME: Remove this when overlapping marker traits are stable
impl<From, T, F, C> SelectableExpression<SelectStatement<FromClause<From>>>
    for AliasedField<Alias<T, F>, C>
where
    Self: SelectableExpression<From> + AppearsOnTable<SelectStatement<FromClause<From>>>,
    From: QuerySource,
{
}

impl<T, Selection, F> AppendSelection<Selection> for Alias<T, F>
where
    T: Table,
    Self: QuerySource,
{
    type Output = (<Self as QuerySource>::DefaultSelection, Selection);

    fn append_selection(&self, selection: Selection) -> Self::Output {
        (self.default_selection(), selection)
    }
}

impl<Lhs, Rhs, On, F> JoinTo<OnClauseWrapper<Rhs, On>> for Alias<Lhs, F> {
    type FromClause = Rhs;
    type OnClause = On;

    fn join_target(rhs: OnClauseWrapper<Rhs, On>) -> (Self::FromClause, Self::OnClause) {
        (rhs.source, rhs.on)
    }
}
<commit_msg>apply fix comment<commit_after>#![warn(missing_docs)]

use super::*;
use crate::associations::HasTable;
use crate::backend::Backend;
use crate::dsl::{Filter, Select};
use crate::expression::{
    is_aggregate, AppearsOnTable, Expression, SelectableExpression, ValidGrouping,
};
use crate::query_builder::nodes::StaticQueryFragment;
use crate::query_builder::{AsQuery, AstPass, FromClause, QueryFragment, QueryId, SelectStatement};
use crate::query_dsl::join_dsl::InternalJoinDsl;
use crate::query_dsl::methods::*;
use crate::query_dsl::QueryDsl;
use crate::query_source::joins::ToInnerJoin;
use crate::query_source::joins::{
    AppendSelection, Inner, Join, JoinOn, LeftOuter, OnClauseWrapper,
};
use crate::query_source::{AppearsInFromClause, Column, Never, Once, QuerySource, Table};
use crate::result::QueryResult;
use std::marker::PhantomData;

#[derive(Debug, Copy)]
pub struct Alias<T, F>(PhantomData<(T, F)>);

#[derive(Debug)]
pub struct AliasedField<A, F>(A, PhantomData<F>);

pub trait Named {
    const NAME: &'static str;
}

pub trait AliasNotEqualHelper<Table2, Alias1, Alias2> {
    type Count;
}

impl<T, F> Clone for Alias<T, F> {
    fn clone(&self) -> Self {
        Alias::new()
    }
}

impl<T, F, C> Clone for AliasedField<Alias<T, F>, C> {
    fn clone(&self) -> Self {
        AliasedField(self.0.clone(), PhantomData)
    }
}

impl<T, F> QueryId for Alias<T, F> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<T, F> Alias<T, F> {
    pub fn new() -> Self {
        Alias(PhantomData)
    }
}

impl<T, F> Alias<T, F>
where
    T: Table,
{
    pub fn field<C>(&self, _: C) -> AliasedField<Self, C>
    where
        C: Column<Table = T>,
    {
        AliasedField(Alias::new(), PhantomData)
    }
}

impl<QS, T, F, C> AppearsOnTable<QS> for AliasedField<Alias<T, F>, C>
where
    QS: AppearsInFromClause<Alias<T, F>, Count = Once>,
    T: Table,
    C: Column<Table = T>,
{
}

impl<T, F, C> QueryId for AliasedField<Alias<T, F>, C>
where
    T: Table + 'static,
    C: Column<Table = T> + 'static,
    F: 'static,
{
    type QueryId = Self;
    const HAS_STATIC_QUERY_ID: bool = true;
}

#[doc(hidden)]
pub trait FieldAliasMapper<A> {
    type Out;

    fn map(self) -> Self::Out;
}

impl<T, F, C> FieldAliasMapper<Alias<T, F>> for C
where
    C: Column<Table = T>,
    T: Table,
{
    type Out = AliasedField<Alias<T, F>, C>;

    fn map(self) -> Self::Out {
        AliasedField(Alias::new(), PhantomData)
    }
}

macro_rules! field_alias_mapper {
    ($(
        $Tuple:tt {
            $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+
        }
    )+) => {
        $(
            impl<_T, _F, $($T,)*> FieldAliasMapper<Alias<_T, _F>> for ($($T,)*) {
                type Out = ($(AliasedField<Alias<_T, _F>, $T>,)*);

                fn map(self) -> Self::Out {
                    (
                        $(AliasedField(Alias::new(), PhantomData::<$T>),)*
                    )
                }
            }
        )*
    }
}

diesel_derives::__diesel_for_each_tuple!(field_alias_mapper);

impl<T, F> QuerySource for Alias<T, F>
where
    T: Table + QuerySource + HasTable<Table = T>,
    T::DefaultSelection: FieldAliasMapper<Self>,
    <T::DefaultSelection as FieldAliasMapper<Self>>::Out: SelectableExpression<Self>,
{
    type FromClause = Self;
    type DefaultSelection = <T::DefaultSelection as FieldAliasMapper<Self>>::Out;

    fn from_clause(&self) -> Self::FromClause {
        Alias::new()
    }

    fn default_selection(&self) -> Self::DefaultSelection {
        T::default_selection(&T::table()).map()
    }
}

impl<T, F, DB> QueryFragment<DB> for Alias<T, F>
where
    DB: Backend,
    T: Table + StaticQueryFragment,
    T::Component: QueryFragment<DB>,
    F: Named,
{
    fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        T::STATIC_COMPONENT.walk_ast(pass.reborrow())?;
        pass.push_sql(" AS ");
        pass.push_identifier(F::NAME)?;
        Ok(())
    }
}

impl<T, F, C, DB> QueryFragment<DB> for AliasedField<Alias<T, F>, C>
where
    DB: Backend,
    T: Table,
    C: Column<Table = T>,
    F: Named,
{
    fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        pass.push_identifier(F::NAME)?;
        pass.push_sql(".");
        pass.push_identifier(C::NAME)?;
        Ok(())
    }
}

impl<T, F, C> Expression for AliasedField<Alias<T, F>, C>
where
    T: Table,
    C: Column<Table = T> + Expression,
{
    type SqlType = C::SqlType;
}

impl<T, F, C> SelectableExpression<Alias<T, F>> for AliasedField<Alias<T, F>, C>
where
    T: Table,
    C: Column<Table = T>,
    Self: AppearsOnTable<Alias<T, F>>,
{
}

impl<T, F, C> ValidGrouping<()> for AliasedField<Alias<T, F>, C>
where
    T: Table,
    C: Column<Table = T>,
{
    type IsAggregate = is_aggregate::No;
}
impl<T, F, C> ValidGrouping<AliasedField<Alias<T, F>, C>> for AliasedField<Alias<T, F>, C>
where
    T: Table,
    C: Column<Table = T>,
{
    type IsAggregate = is_aggregate::Yes;
}

impl<T, F> AsQuery for Alias<T, F>
where
    T: AsQuery + Table + HasTable<Table = T>,
    Self: QuerySource,
    <Self as QuerySource>::DefaultSelection: ValidGrouping<()>,
{
    type SqlType = <<Self as QuerySource>::DefaultSelection as Expression>::SqlType;
    type Query = SelectStatement<FromClause<Self>>;

    fn as_query(self) -> Self::Query {
        SelectStatement::simple(self)
    }
}

impl<T1, T2, F1, F2> AppearsInFromClause<Alias<T1, F1>> for Alias<T2, F2>
where
    T2: AliasNotEqualHelper<T1, F2, F1>,
{
    type Count = T2::Count;
}

impl<T, F> AppearsInFromClause<Alias<T, F>> for ()
where
    T: Table,
{
    type Count = Never;
}

impl<T, F> QueryDsl for Alias<T, F> where T: Table {}

impl<T, F, Predicate> FilterDsl<Predicate> for Alias<T, F>
where
    T: Table,
    Self: AsQuery,
    <Self as AsQuery>::Query: FilterDsl<Predicate>,
{
    type Output = Filter<<Self as AsQuery>::Query, Predicate>;

    fn filter(self, predicate: Predicate) -> Self::Output {
        self.as_query().filter(predicate)
    }
}

impl<T, F, Selection> SelectDsl<Selection> for Alias<T, F>
where
    Selection: Expression,
    Self: AsQuery,
    T: Table,
    <Self as AsQuery>::Query: SelectDsl<Selection>,
{
    type Output = Select<<Self as AsQuery>::Query, Selection>;

    fn select(self, selection: Selection) -> Self::Output {
        self.as_query().select(selection)
    }
}

#[macro_export]
macro_rules! __internal_alias_helper {
    (
        $left_table: ident as $left_alias: ident,
        $right_table: ident as $right_alias: ident,
        $($table: ident as $alias: ident,)*
    ) => {
        static_cond!{if $left_table == $right_table {
            impl $crate::query_source::AliasNotEqualHelper<$left_table::table, $right_alias, $left_alias> for $right_table::table {
                type Count = $crate::query_source::Never;
            }

            impl $crate::query_source::AliasNotEqualHelper<$right_table::table, $left_alias, $right_alias> for $left_table::table {
                type Count = $crate::query_source::Never;
            }
        }}

        __internal_alias_helper!($left_table as $left_alias, $($table as $alias,)*);
        __internal_alias_helper!($right_table as $right_alias, $($table as $alias,)*);
    };

    ($table: ident as $alias: ident,) => {}
}

/// TODO
#[macro_export]
macro_rules! alias {
    ($($table: ident as $alias: ident),* $(,)?) => {{
        $(
            #[allow(non_camel_case_types)]
            #[derive(Debug, Clone, Copy)]
            struct $alias;

            impl $crate::query_source::Named for $alias {
                const NAME: &'static str = stringify!($alias);
            }

            impl
                $crate::query_source::AppearsInFromClause<
                $crate::query_source::Alias<$table::table, $alias>,
            > for $table::table
            {
                type Count = $crate::query_source::Never;
            }

            impl $crate::query_source::AppearsInFromClause<$table::table>
                for $crate::query_source::Alias<$table::table, $alias>
            {
                type Count = $crate::query_source::Never;
            }

            impl $crate::query_source::AliasNotEqualHelper<$table::table, $alias, $alias> for $table::table {
                type Count = $crate::query_source::Once;
            }
        )*
        __internal_alias_helper!($($table as $alias,)*);
        ($($crate::query_source::Alias::<$table::table, $alias>::new()),*)
    }};
}

impl<T: Table, F> ToInnerJoin for Alias<T, F> {
    type InnerJoin = Self;
}

impl<T, Rhs, Kind, On, F> InternalJoinDsl<Rhs, Kind, On> for Alias<T, F>
where
    Self: AsQuery,
    <Self as AsQuery>::Query: InternalJoinDsl<Rhs, Kind, On>,
{
    type Output = <<Self as AsQuery>::Query as InternalJoinDsl<Rhs, Kind, On>>::Output;

    fn join(self, rhs: Rhs, kind: Kind, on: On) -> Self::Output {
        self.as_query().join(rhs, kind, on)
    }
}

impl<Left, Right, T, F, C> SelectableExpression<Join<Left, Right, LeftOuter>>
    for AliasedField<Alias<T, F>, C>
where
    Self: AppearsOnTable<Join<Left, Right, LeftOuter>>,
    Self: SelectableExpression<Left>,
    Left: QuerySource,
    Right: AppearsInFromClause<Alias<T, F>, Count = Never> + QuerySource,
{
}

impl<Left, Right, T, F, C> SelectableExpression<Join<Left, Right, Inner>>
    for AliasedField<Alias<T, F>, C>
where
    Self: AppearsOnTable<Join<Left, Right, Inner>>,
    Left: AppearsInFromClause<Alias<T, F>> + QuerySource,
    Right: AppearsInFromClause<Alias<T, F>> + QuerySource,
    (Left::Count, Right::Count): Pick<Left, Right>,
    Self: SelectableExpression<<(Left::Count, Right::Count) as Pick<Left, Right>>::Selection>,
{
}

// FIXME: Remove this when overlapping marker traits are stable
impl<Join, On, T, F, C> SelectableExpression<JoinOn<Join, On>> for AliasedField<Alias<T, F>, C> where
    Self: SelectableExpression<Join> + AppearsOnTable<JoinOn<Join, On>>
{
}

// FIXME: Remove this when overlapping marker traits are stable
impl<From, T, F, C> SelectableExpression<SelectStatement<FromClause<From>>>
    for AliasedField<Alias<T, F>, C>
where
    Self: SelectableExpression<From> + AppearsOnTable<SelectStatement<FromClause<From>>>,
    From: QuerySource,
{
}

impl<T, Selection, F> AppendSelection<Selection> for Alias<T, F>
where
    T: Table,
    Self: QuerySource,
{
    type Output = (<Self as QuerySource>::DefaultSelection, Selection);

    fn append_selection(&self, selection: Selection) -> Self::Output {
        (self.default_selection(), selection)
    }
}

impl<Lhs, Rhs, On, F> JoinTo<OnClauseWrapper<Rhs, On>> for Alias<Lhs, F> {
    type FromClause = Rhs;
    type OnClause = On;

    fn join_target(rhs: OnClauseWrapper<Rhs, On>) -> (Self::FromClause, Self::OnClause) {
        (rhs.source, rhs.on)
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::env;
use std::io::BufReader;
use std::io::BufRead;
use std::io::Write;
use std::collections::HashMap;
use std::collections::BTreeMap;
use std::collections::BTreeSet;

extern crate tools;
use tools::find_source_file;
use tools::file_format::analysis::{read_analysis, read_target, AnalysisKind};
use tools::config;

extern crate rustc_serialize;
use rustc_serialize::json::{Json, ToJson};

#[derive(Debug)]
struct SearchResult {
    lineno: u32,
    bounds: (u32, u32),
    line: String,
    context: String,
    contextsym: String,
}

impl ToJson for SearchResult {
    fn to_json(&self) -> Json {
        let (st, en) = self.bounds;
        let bounds = vec![st, en];

        let mut obj = BTreeMap::new();
        obj.insert("lno".to_string(), self.lineno.to_json());
        obj.insert("bounds".to_string(), bounds.to_json());
        obj.insert("line".to_string(), self.line.to_json());
        obj.insert("context".to_string(), self.context.to_json());
        obj.insert("contextsym".to_string(), self.contextsym.to_json());
        Json::Object(obj)
    }
}

fn split_scopes(id: &str) -> Vec<String> {
    let mut result = Vec::new();
    let mut start = 0;
    let mut argument_nesting = 0;
    for (index, m) in id.match_indices(|c| c == ':' || c == '<' || c == '>') {
        if m == ":" && argument_nesting == 0 {
            if start != index {
                result.push(id[start .. index].to_owned());
                start = index + 1;
            } else {
                start = index + 1;
            }
        } else if m == "<" {
            argument_nesting += 1;
        } else if m == ">" {
            argument_nesting -= 1;
        }
    }
    result.push(id[start ..].to_owned());
    return result;
}

fn main() {
    let args: Vec<_> = env::args().collect();

    let cfg = config::load(&args[1], false);

    let tree_name = &args[2];
    let tree_config = cfg.trees.get(tree_name).unwrap();

    let filenames_file = &args[3];

    let file_paths: Vec<String> = BufReader::new(File::open(filenames_file).unwrap())
        .lines().map(|x| x.unwrap()).collect();
    let output_file = format!("{}/crossref", tree_config.paths.index_path);
    let jump_file = format!("{}/jumps", tree_config.paths.index_path);
    let id_file = format!("{}/identifiers", tree_config.paths.index_path);

    let mut table = BTreeMap::new();
    let mut pretty_table = HashMap::new();
    let mut id_table = BTreeMap::new();
    let mut jumps = Vec::new();

    {
        for path in &file_paths {
            print!("File {}\n", path);

            let analysis_fname = format!("{}/analysis/{}", tree_config.paths.index_path, path);
            let analysis = read_analysis(&analysis_fname, &read_target);

            let source_fname = find_source_file(path, &tree_config.paths.files_path, &tree_config.paths.objdir_path);
            let source_file = match File::open(source_fname) {
                Ok(f) => f,
                Err(_) => {
                    println!("Unable to open source file");
                    continue;
                },
            };
            let reader = BufReader::new(&source_file);
            let mut lines = Vec::new();
            for line in reader.lines() {
                match line {
                    Ok(l) => lines.push(l),
                    Err(_) => lines.push("".to_string()),
                }
            }

            for datum in analysis {
                for piece in datum.data {
                    let t1 = table.entry(piece.sym.to_owned()).or_insert(BTreeMap::new());
                    let t2 = t1.entry(piece.kind).or_insert(BTreeMap::new());
                    let p: &str = &path;
                    let t3 = t2.entry(p).or_insert(Vec::new());
                    let lineno = (datum.loc.lineno - 1) as usize;
                    if lineno >= lines.len() {
                        print!("Bad line number in file {} (line {})\n", path, lineno);
                        continue;
                    }
                    let line = lines[lineno].clone();
                    let line_cut = line.trim_right();
                    let len = line_cut.len();
                    let line_cut = line_cut.trim_left();
                    let offset = (len - line_cut.len()) as u32;
                    let mut buf = String::new();
                    let mut i = 0;
                    for c in line_cut.chars() {
                        buf.push(c);
                        i += 1;
                        if i > 100 {
                            break;
                        }
                    }
                    t3.push(SearchResult {
                        lineno: datum.loc.lineno,
                        bounds: (datum.loc.col_start - offset, datum.loc.col_end - offset),
                        line: buf,
                        context: piece.context,
                        contextsym: piece.contextsym,
                    });

                    pretty_table.insert(piece.sym.to_owned(), piece.pretty.to_owned());

                    let ch = piece.sym.chars().nth(0).unwrap();
                    if !(ch >= '0' && ch <= '9') && !piece.sym.contains(' ') {
                        let t1 = id_table.entry(piece.pretty.to_owned()).or_insert(BTreeSet::new());
                        t1.insert(piece.sym.to_owned());
                    }
                }
            }
        }
    }

    let mut outputf = File::create(output_file).unwrap();

    for (id, id_data) in table {
        let mut kindmap = BTreeMap::new();
        for (kind, kind_data) in &id_data {
            let mut result = Vec::new();
            for (path, results) in kind_data {
                let mut obj = BTreeMap::new();
                obj.insert("path".to_string(), path.to_json());
                obj.insert("lines".to_string(), results.to_json());
                result.push(Json::Object(obj));
            }
            let kindstr = match *kind {
                AnalysisKind::Use => "Uses",
                AnalysisKind::Def => "Definitions",
                AnalysisKind::Assign => "Assignments",
                AnalysisKind::Decl => "Declarations",
                AnalysisKind::Idl => "IDL",
            };
            kindmap.insert(kindstr.to_string(), Json::Array(result));
        }
        let kindmap = Json::Object(kindmap);

        let _ = outputf.write_all(format!("{}\n{}\n", id, kindmap.to_string()).as_bytes());

        if id_data.contains_key(&AnalysisKind::Def) {
            let defs = id_data.get(&AnalysisKind::Def).unwrap();
            if defs.len() == 1 {
                for (path, results) in defs {
                    if results.len() == 1 {
                        let mut v = Vec::new();
                        v.push(id.to_json());
                        v.push(path.to_json());
                        v.push(results[0].lineno.to_json());
                        let pretty = pretty_table.get(&id).unwrap();
                        v.push(pretty.to_json());
                        jumps.push(Json::Array(v));
                    }
                }
            }
        }
    }

    let mut jumpf = File::create(jump_file).unwrap();
    for jump in jumps {
        let _ = jumpf.write_all((jump.to_string() + "\n").as_bytes());
    }

    let mut idf = File::create(id_file).unwrap();
    for (id, syms) in id_table {
        for sym in syms {
            let components = split_scopes(&id);
            for i in 0..components.len() {
                let sub = &components[i..components.len()];
                let sub = sub.join("::");

                if !sub.is_empty() {
                    let line = format!("{} {}\n", sub, sym);
                    let _ = idf.write_all(line.as_bytes());
                }
            }
        }
    }
}
<commit_msg>Bug 1415700, part 2 - Remove extra scope.<commit_after>use std::fs::File;
use std::env;
use std::io::BufReader;
use std::io::BufRead;
use std::io::Write;
use std::collections::HashMap;
use std::collections::BTreeMap;
use std::collections::BTreeSet;

extern crate tools;
use tools::find_source_file;
use tools::file_format::analysis::{read_analysis, read_target, AnalysisKind};
use tools::config;

extern crate rustc_serialize;
use rustc_serialize::json::{Json, ToJson};

#[derive(Debug)]
struct SearchResult {
    lineno: u32,
    bounds: (u32, u32),
    line: String,
    context: String,
    contextsym: String,
}

impl ToJson for SearchResult {
    fn to_json(&self) -> Json {
        let (st, en) = self.bounds;
        let bounds = vec![st, en];

        let mut obj = BTreeMap::new();
        obj.insert("lno".to_string(), self.lineno.to_json());
        obj.insert("bounds".to_string(), bounds.to_json());
        obj.insert("line".to_string(), self.line.to_json());
        obj.insert("context".to_string(), self.context.to_json());
        obj.insert("contextsym".to_string(), self.contextsym.to_json());
        Json::Object(obj)
    }
}

fn split_scopes(id: &str) -> Vec<String> {
    let mut result = Vec::new();
    let mut start = 0;
    let mut argument_nesting = 0;
    for (index, m) in id.match_indices(|c| c == ':' || c == '<' || c == '>') {
        if m == ":" && argument_nesting == 0 {
            if start != index {
                result.push(id[start .. index].to_owned());
                start = index + 1;
            } else {
                start = index + 1;
            }
        } else if m == "<" {
            argument_nesting += 1;
        } else if m == ">" {
            argument_nesting -= 1;
        }
    }
    result.push(id[start ..].to_owned());
    return result;
}

fn main() {
    let args: Vec<_> = env::args().collect();

    let cfg = config::load(&args[1], false);

    let tree_name = &args[2];
    let tree_config = cfg.trees.get(tree_name).unwrap();

    let filenames_file = &args[3];

    let file_paths: Vec<String> = BufReader::new(File::open(filenames_file).unwrap())
        .lines().map(|x| x.unwrap()).collect();
    let output_file = format!("{}/crossref", tree_config.paths.index_path);
    let jump_file = format!("{}/jumps", tree_config.paths.index_path);
    let id_file = format!("{}/identifiers", tree_config.paths.index_path);

    let mut table = BTreeMap::new();
    let mut pretty_table = HashMap::new();
    let mut id_table = BTreeMap::new();
    let mut jumps = Vec::new();

    for path in &file_paths {
        print!("File {}\n", path);

        let analysis_fname = format!("{}/analysis/{}", tree_config.paths.index_path, path);
        let analysis = read_analysis(&analysis_fname, &read_target);

        let source_fname = find_source_file(path, &tree_config.paths.files_path, &tree_config.paths.objdir_path);
        let source_file = match File::open(source_fname) {
            Ok(f) => f,
            Err(_) => {
                println!("Unable to open source file");
                continue;
            },
        };
        let reader = BufReader::new(&source_file);
        let mut lines = Vec::new();
        for line in reader.lines() {
            match line {
                Ok(l) => lines.push(l),
                Err(_) => lines.push("".to_string()),
            }
        }

        for datum in analysis {
            for piece in datum.data {
                let t1 = table.entry(piece.sym.to_owned()).or_insert(BTreeMap::new());
                let t2 = t1.entry(piece.kind).or_insert(BTreeMap::new());
                let p: &str = &path;
                let t3 = t2.entry(p).or_insert(Vec::new());
                let lineno = (datum.loc.lineno - 1) as usize;
                if lineno >= lines.len() {
                    print!("Bad line number in file {} (line {})\n", path, lineno);
                    continue;
                }
                let line = lines[lineno].clone();
                let line_cut = line.trim_right();
                let len = line_cut.len();
                let line_cut = line_cut.trim_left();
                let offset = (len - line_cut.len()) as u32;
                let mut buf = String::new();
                let mut i = 0;
                for c in line_cut.chars() {
                    buf.push(c);
                    i += 1;
                    if i > 100 {
                        break;
                    }
                }
                t3.push(SearchResult {
                    lineno: datum.loc.lineno,
                    bounds: (datum.loc.col_start - offset, datum.loc.col_end - offset),
                    line: buf,
                    context: piece.context,
                    contextsym: piece.contextsym,
                });

                pretty_table.insert(piece.sym.to_owned(), piece.pretty.to_owned());

                let ch = piece.sym.chars().nth(0).unwrap();
                if !(ch >= '0' && ch <= '9') && !piece.sym.contains(' ') {
                    let t1 = id_table.entry(piece.pretty.to_owned()).or_insert(BTreeSet::new());
                    t1.insert(piece.sym.to_owned());
                }
            }
        }
    }

    let mut outputf = File::create(output_file).unwrap();

    for (id, id_data) in table {
        let mut kindmap = BTreeMap::new();
        for (kind, kind_data) in &id_data {
            let mut result = Vec::new();
            for (path, results) in kind_data {
                let mut obj = BTreeMap::new();
                obj.insert("path".to_string(), path.to_json());
                obj.insert("lines".to_string(), results.to_json());
                result.push(Json::Object(obj));
            }
            let kindstr = match *kind {
                AnalysisKind::Use => "Uses",
                AnalysisKind::Def => "Definitions",
                AnalysisKind::Assign => "Assignments",
                AnalysisKind::Decl => "Declarations",
                AnalysisKind::Idl => "IDL",
            };
            kindmap.insert(kindstr.to_string(), Json::Array(result));
        }
        let kindmap = Json::Object(kindmap);

        let _ = outputf.write_all(format!("{}\n{}\n", id, kindmap.to_string()).as_bytes());

        if id_data.contains_key(&AnalysisKind::Def) {
            let defs = id_data.get(&AnalysisKind::Def).unwrap();
            if defs.len() == 1 {
                for (path, results) in defs {
                    if results.len() == 1 {
                        let mut v = Vec::new();
                        v.push(id.to_json());
                        v.push(path.to_json());
                        v.push(results[0].lineno.to_json());
                        let pretty = pretty_table.get(&id).unwrap();
                        v.push(pretty.to_json());
                        jumps.push(Json::Array(v));
                    }
                }
            }
        }
    }

    let mut jumpf = File::create(jump_file).unwrap();
    for jump in jumps {
        let _ = jumpf.write_all((jump.to_string() + "\n").as_bytes());
    }

    let mut idf = File::create(id_file).unwrap();
    for (id, syms) in id_table {
        for sym in syms {
            let components = split_scopes(&id);
            for i in 0..components.len() {
                let sub = &components[i..components.len()];
                let sub = sub.join("::");

                if !sub.is_empty() {
                    let line = format!("{} {}\n", sub, sym);
                    let _ = idf.write_all(line.as_bytes());
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::mem;

use self::BufferedParserState::{Beginning, Middle, EndMatch, EndFail};
use self::MatchResult::{Undecided, Committed, Matched, Failed};
use self::ConstantParserState::{AtOffset, AtEnd};

// ----------- Types with lifetimes -------------

// Borrowing encoding of paramaterized types from
// https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md#encoding-higher-kinded-types

pub trait TypeWithLifetime<'a> {
    type Type;
}

pub type At<'a,T> where T: TypeWithLifetime<'a> = T::Type;

pub struct Always<T> (T);

impl<'a,T> TypeWithLifetime<'a> for Always<T> {
    type Type = T;
}

pub type Unit = Always<()>;

// ----------- Types for consumers ------------

pub trait Consumer<T> where T: 'static+for<'a> TypeWithLifetime<'a> {
    fn accept<'a>(&mut self, arg: At<'a,T>);
}

struct DiscardConsumer;

impl Consumer<Unit> for DiscardConsumer {
    fn accept(&mut self, _: ()) {}
}

// ----------- Types for parsers ------------

// State machine transitions are:
//
// init -Undecided->  init
// init -Committed->  committed
// init -Matched(s)-> matched
// init -Failed(b)->  failed(b)
//
// committed -Committed->     committed
// committed -Matched(s)->    matched
// committed -Failed(false)-> failed(false)
//
// matched -Matched(s)-> matched
//
// failed(b) -Failed(b)-> failed(b)
//
// The Failed(b) action carries a boolean indicating if backtracking is allowed.
// Note that there is no transition . -Committed-> . -Failed(true)-> . so
// once a parser has committed, we can clean up space associated with backtracking.

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum MatchResult<T> {
    Undecided,
    Committed,
    Matched(T),
    Failed(bool),
}

pub trait Parser<S,T> where S: 'static+for<'a> TypeWithLifetime<'a>, T: 'static+for<'a> TypeWithLifetime<'a> {
    // If push returns Undecided or Failed(true), it is side-effect-free
    // In the case where T is "list-like" (e.g. &str or &[T])
    // push(nil) is a no-op
    // push(a ++ b) is the same as push(a); push(b)
    fn push<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>>;
    // Resets the parser state back to its initial state
    // Returns true if there was a match.
    fn done(&mut self, downstream: &mut Consumer<T>) -> bool;
}

pub trait BufferableMatcher<S,T> where S: 'static+for<'a> TypeWithLifetime<'a>, T: Parser<S,S> {
    fn buffer(self) -> T;
}

// ----------- Always commit ---------------

pub struct CommittedParser<P> {
    parser: P,
}

impl<S,T,P> Parser<S,T> for CommittedParser<P> where P: Parser<S,T>, S: 'static+for<'a> TypeWithLifetime<'a>, T: 'static+for<'a> TypeWithLifetime<'a>  {
    fn push<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        match self.parser.push(value, downstream) {
            Undecided     => Committed,
            Committed     => Committed,
            Matched(rest) => Matched(rest),
            Failed(_)     => Failed(false),
        }
    }
    fn done(&mut self, downstream: &mut Consumer<T>) -> bool {
        self.parser.done(downstream)
    }
}

// ----------- Sequencing ---------------

pub struct AndThenParser<L,R> {
    lhs: L,
    rhs: CommittedParser<R>,
    in_lhs: bool,
}

impl<S,T,L,R> Parser<S,T> for AndThenParser<L,R> where L: Parser<S,T>, R: Parser<S,T>, S: 'static+for<'a> TypeWithLifetime<'a>, T: 'static+for<'a> TypeWithLifetime<'a>  {
    fn push<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        if self.in_lhs {
            match self.lhs.push(value, downstream) {
                Undecided     => Undecided,
                Committed     => Committed,
                Matched(rest) => { self.in_lhs = false; self.rhs.push(rest, downstream) },
                Failed(b)     => Failed(b),
            }
        } else {
            self.rhs.push(value, downstream)
        }
    }
    fn done(&mut self, downstream: &mut Consumer<T>) -> bool {
        self.lhs.done(downstream) && self.rhs.done(downstream)
    }
}

// ----------- Matching strings -------------

pub struct Str;

impl<'a> TypeWithLifetime<'a> for Str {
    type Type = &'a str;
}

// ----------- Constant parsers -------------

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum ConstantParserState {
    AtOffset(usize),
    AtEnd(bool),
}

pub struct ConstantParser {
    constant: String,
    state: ConstantParserState,
}

impl Parser<Str,Unit> for ConstantParser {
    fn push<'a>(&mut self, string: &'a str, downstream: &mut Consumer<Unit>) -> MatchResult<&'a str> {
        match self.state {
            AtOffset(index) if string.starts_with(&self.constant[index..]) => { downstream.accept(()); self.state = AtEnd(true); Matched(&string[(self.constant.len() - index)..]) },
            AtOffset(index) if self.constant[index..].starts_with(string)  => { self.state = AtOffset(index + string.len()); Undecided },
            AtOffset(_)                                                    => { self.state = AtEnd(false); Failed(true) },
            AtEnd(true)                                                    => { Matched(string) },
            AtEnd(false)                                                   => { Failed(true) },
        }
    }
    fn done(&mut self, _: &mut Consumer<Unit>) -> bool {
        let result = self.state == AtEnd(true);
        self.state = AtOffset(0);
        result
    }
}

pub fn constant(string: String) -> ConstantParser {
    ConstantParser{ constant: string, state: AtOffset(0) }
}

// If m is a Parser<Str,Unit> then m.buffer() is a Parser<Str,Str>.
// It does as little buffering as it can, but it does allocate as buffer for the case
// where the boundary marker of the input is misaligned with that of the parser.
// For example, m is matching string literals, and the input is '"abc' followed by 'def"'
// we have to buffer up '"abc'.

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
enum BufferedParserState {
    Beginning,
    Middle(String),
    EndMatch,
    EndFail(bool),
}

pub struct BufferedParser<P> {
    parser: P,
    state: BufferedParserState,
}

impl<P> Parser<Str,Str> for BufferedParser<P> where P: Parser<Str,Unit> {
    fn push<'a>(&mut self, string: &'a str, downstream: &mut Consumer<Str>) -> MatchResult<&'a str> {
        match mem::replace(&mut self.state, EndMatch) {
            Beginning => {
                let result = self.parser.push(string, &mut DiscardConsumer);
                match result {
                    Undecided     => self.state = Middle(String::from(string)),
                    Committed     => self.state = Middle(String::from(string)),
                    Failed(b)     => self.state = EndFail(b),
                    Matched(rest) => downstream.accept(&string[..(string.len()-rest.len())]),
                }
                result
            },
            Middle(mut buffer) => {
                let result = self.parser.push(string, &mut DiscardConsumer);
                match result {
                    Undecided     => { buffer.push_str(string); self.state = Middle(buffer); },
                    Committed     => { buffer.push_str(string); self.state = Middle(buffer); },
                    Failed(b)     => { self.state = EndFail(b); },
                    Matched(rest) => { buffer.push_str(&string[..(string.len()-rest.len())]); downstream.accept(&*buffer); },
                }
                result
            }
            EndMatch => Matched(string),
            EndFail(b) => Failed(b),
        }
    }
    fn done(&mut self, downstream: &mut Consumer<Str>) -> bool {
        let result = self.parser.done(&mut DiscardConsumer);
        if result { if let Middle(ref buffer) = self.state { downstream.accept(&*buffer) } }
        self.state = Beginning;
        result
    }
}

#[test]
fn test_constant() {
    let mut parser = constant(String::from("abc"));
    assert_eq!(parser.done(&mut DiscardConsumer), false);
    assert_eq!(parser.push("fred", &mut DiscardConsumer), Failed(true));
    assert_eq!(parser.done(&mut DiscardConsumer), false);
    assert_eq!(parser.push("abcdef", &mut DiscardConsumer), Matched("def"));
    assert_eq!(parser.done(&mut DiscardConsumer), true);
    assert_eq!(parser.push("a", &mut DiscardConsumer), Undecided);
    assert_eq!(parser.done(&mut DiscardConsumer), false);
    assert_eq!(parser.push("ab", &mut DiscardConsumer), Undecided);
    assert_eq!(parser.push("cd", &mut DiscardConsumer), Matched("d"));
    assert_eq!(parser.done(&mut DiscardConsumer), true);
}
<commit_msg>Removed no-longer-needed static restrictions.<commit_after>use std::mem;

use self::BufferedParserState::{Beginning, Middle, EndMatch, EndFail};
use self::MatchResult::{Undecided, Committed, Matched, Failed};
use self::ConstantParserState::{AtOffset, AtEnd};

// ----------- Types with lifetimes -------------

// Borrowing encoding of paramaterized types from
// https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md#encoding-higher-kinded-types

pub trait TypeWithLifetime<'a> {
    type Type;
}

pub type At<'a,T> where T: TypeWithLifetime<'a> = T::Type;

pub struct Always<T> (T);

impl<'a,T> TypeWithLifetime<'a> for Always<T> {
    type Type = T;
}

pub type Unit = Always<()>;

// ----------- Types for consumers ------------

pub trait Consumer<T> where T: for<'a> TypeWithLifetime<'a> {
    fn accept<'a>(&mut self, arg: At<'a,T>);
}

struct DiscardConsumer;

impl Consumer<Unit> for DiscardConsumer {
    fn accept(&mut self, _: ()) {}
}

// ----------- Types for parsers ------------

// State machine transitions are:
//
// init -Undecided->  init
// init -Committed->  committed
// init -Matched(s)-> matched
// init -Failed(b)->  failed(b)
//
// committed -Committed->     committed
// committed -Matched(s)->    matched
// committed -Failed(false)-> failed(false)
//
// matched -Matched(s)-> matched
//
// failed(b) -Failed(b)-> failed(b)
//
// The Failed(b) action carries a boolean indicating if backtracking is allowed.
// Note that there is no transition . -Committed-> . -Failed(true)-> . so
// once a parser has committed, we can clean up space associated with backtracking.

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum MatchResult<T> {
    Undecided,
    Committed,
    Matched(T),
    Failed(bool),
}

pub trait Parser<S,T> where S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a> {
    // If push returns Undecided or Failed(true), it is side-effect-free
    // In the case where T is "list-like" (e.g. &str or &[T])
    // push(nil) is a no-op
    // push(a ++ b) is the same as push(a); push(b)
    fn push<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>>;
    // Resets the parser state back to its initial state
    // Returns true if there was a match.
    fn done(&mut self, downstream: &mut Consumer<T>) -> bool;
}

pub trait BufferableMatcher<S,T> where S: for<'a> TypeWithLifetime<'a>, T: Parser<S,S> {
    fn buffer(self) -> T;
}

// ----------- Always commit ---------------

pub struct CommittedParser<P> {
    parser: P,
}

impl<S,T,P> Parser<S,T> for CommittedParser<P> where P: Parser<S,T>, S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a>  {
    fn push<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        match self.parser.push(value, downstream) {
            Undecided     => Committed,
            Committed     => Committed,
            Matched(rest) => Matched(rest),
            Failed(_)     => Failed(false),
        }
    }
    fn done(&mut self, downstream: &mut Consumer<T>) -> bool {
        self.parser.done(downstream)
    }
}

// ----------- Sequencing ---------------

pub struct AndThenParser<L,R> {
    lhs: L,
    rhs: CommittedParser<R>,
    in_lhs: bool,
}

impl<S,T,L,R> Parser<S,T> for AndThenParser<L,R> where L: Parser<S,T>, R: Parser<S,T>, S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a>  {
    fn push<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        if self.in_lhs {
            match self.lhs.push(value, downstream) {
                Undecided     => Undecided,
                Committed     => Committed,
                Matched(rest) => { self.in_lhs = false; self.rhs.push(rest, downstream) },
                Failed(b)     => Failed(b),
            }
        } else {
            self.rhs.push(value, downstream)
        }
    }
    fn done(&mut self, downstream: &mut Consumer<T>) -> bool {
        self.lhs.done(downstream) && self.rhs.done(downstream)
    }
}

// ----------- Matching strings -------------

pub struct Str;

impl<'a> TypeWithLifetime<'a> for Str {
    type Type = &'a str;
}

// ----------- Constant parsers -------------

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum ConstantParserState {
    AtOffset(usize),
    AtEnd(bool),
}

pub struct ConstantParser {
    constant: String,
    state: ConstantParserState,
}

impl Parser<Str,Unit> for ConstantParser {
    fn push<'a>(&mut self, string: &'a str, downstream: &mut Consumer<Unit>) -> MatchResult<&'a str> {
        match self.state {
            AtOffset(index) if string.starts_with(&self.constant[index..]) => { downstream.accept(()); self.state = AtEnd(true); Matched(&string[(self.constant.len() - index)..]) },
            AtOffset(index) if self.constant[index..].starts_with(string)  => { self.state = AtOffset(index + string.len()); Undecided },
            AtOffset(_)                                                    => { self.state = AtEnd(false); Failed(true) },
            AtEnd(true)                                                    => { Matched(string) },
            AtEnd(false)                                                   => { Failed(true) },
        }
    }
    fn done(&mut self, _: &mut Consumer<Unit>) -> bool {
        let result = self.state == AtEnd(true);
        self.state = AtOffset(0);
        result
    }
}

pub fn constant(string: String) -> ConstantParser {
    ConstantParser{ constant: string, state: AtOffset(0) }
}

// If m is a Parser<Str,Unit> then m.buffer() is a Parser<Str,Str>.
// It does as little buffering as it can, but it does allocate as buffer for the case
// where the boundary marker of the input is misaligned with that of the parser.
// For example, m is matching string literals, and the input is '"abc' followed by 'def"'
// we have to buffer up '"abc'.

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
enum BufferedParserState {
    Beginning,
    Middle(String),
    EndMatch,
    EndFail(bool),
}

pub struct BufferedParser<P> {
    parser: P,
    state: BufferedParserState,
}

impl<P> Parser<Str,Str> for BufferedParser<P> where P: Parser<Str,Unit> {
    fn push<'a>(&mut self, string: &'a str, downstream: &mut Consumer<Str>) -> MatchResult<&'a str> {
        match mem::replace(&mut self.state, EndMatch) {
            Beginning => {
                let result = self.parser.push(string, &mut DiscardConsumer);
                match result {
                    Undecided     => self.state = Middle(String::from(string)),
                    Committed     => self.state = Middle(String::from(string)),
                    Failed(b)     => self.state = EndFail(b),
                    Matched(rest) => downstream.accept(&string[..(string.len()-rest.len())]),
                }
                result
            },
            Middle(mut buffer) => {
                let result = self.parser.push(string, &mut DiscardConsumer);
                match result {
                    Undecided     => { buffer.push_str(string); self.state = Middle(buffer); },
                    Committed     => { buffer.push_str(string); self.state = Middle(buffer); },
                    Failed(b)     => { self.state = EndFail(b); },
                    Matched(rest) => { buffer.push_str(&string[..(string.len()-rest.len())]); downstream.accept(&*buffer); },
                }
                result
            }
            EndMatch => Matched(string),
            EndFail(b) => Failed(b),
        }
    }
    fn done(&mut self, downstream: &mut Consumer<Str>) -> bool {
        let result = self.parser.done(&mut DiscardConsumer);
        if result { if let Middle(ref buffer) = self.state { downstream.accept(&*buffer) } }
        self.state = Beginning;
        result
    }
}

#[test]
fn test_constant() {
    let mut parser = constant(String::from("abc"));
    assert_eq!(parser.done(&mut DiscardConsumer), false);
    assert_eq!(parser.push("fred", &mut DiscardConsumer), Failed(true));
    assert_eq!(parser.done(&mut DiscardConsumer), false);
    assert_eq!(parser.push("abcdef", &mut DiscardConsumer), Matched("def"));
    assert_eq!(parser.done(&mut DiscardConsumer), true);
    assert_eq!(parser.push("a", &mut DiscardConsumer), Undecided);
    assert_eq!(parser.done(&mut DiscardConsumer), false);
    assert_eq!(parser.push("ab", &mut DiscardConsumer), Undecided);
    assert_eq!(parser.push("cd", &mut DiscardConsumer), Matched("d"));
    assert_eq!(parser.done(&mut DiscardConsumer), true);
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#[macro_use]
extern crate scan_fmt;

mod common;
mod decoder;
mod muxer;
use crate::common::*;
use rav1e::*;

use std::io;
use std::io::Write;
use std::io::Read;
use std::path::Path;
use std::sync::Arc;
use crate::decoder::Decoder;
use crate::decoder::VideoDetails;
use crate::muxer::*;
use std::fs::File;
use std::io::BufWriter;

struct Source<D: Decoder> {
 limit: usize,
 count: usize,
 input: D,
 #[cfg(feature = "signal-hook")]
 exit_requested: Arc<std::sync::atomic::AtomicBool>,
}

impl<D: Decoder> Source<D> {
  fn read_frame<T: Pixel>(&mut self, ctx: &mut Context<T>, video_info: VideoDetails) {
    if self.limit != 0 && self.count == self.limit {
      ctx.flush();
      return;
    }

    #[cfg(feature = "signal-hook")] {
      if self.exit_requested.load(std::sync::atomic::Ordering::SeqCst) {
        ctx.flush();
        return;
      }
    }

    match self.input.read_frame(&video_info) {
      Ok(frame) => {
        match video_info.bit_depth {
          8 | 10 | 12 => {}
          _ => panic!("unknown input bit depth!")
        }
        self.count += 1;
        let _ = ctx.send_frame(Some(Arc::new(frame)));
      }
      _ => {
        ctx.flush();
      }
    };
  }
}

// Encode and write a frame.
// Returns frame information in a `Result`.
fn process_frame<T: Pixel, D: Decoder>(
  ctx: &mut Context<T>, output_file: &mut dyn Muxer,
  source: &mut Source<D>,
  mut y4m_enc: Option<&mut y4m::Encoder<'_, Box<dyn Write>>>
) -> Option<Vec<FrameSummary>> {
  let y4m_details = source.input.get_video_details();
  let mut frame_summaries = Vec::new();
  let pkt_wrapped = ctx.receive_packet();
  match pkt_wrapped {
    Ok(pkt) => {
      output_file.write_frame(pkt.number as u64, pkt.data.as_ref());
      if let (Some(ref mut y4m_enc_uw), Some(ref rec)) = (y4m_enc.as_mut(), &pkt.rec) {
        write_y4m_frame(y4m_enc_uw, rec, y4m_details);
      }
      frame_summaries.push(pkt.into());
    }
    Err(EncoderStatus::NeedMoreData) => {
      source.read_frame(ctx, y4m_details);
    }
    Err(EncoderStatus::EnoughData) => {
      unreachable!();
    }
    Err(EncoderStatus::LimitReached) => {
      return None;
    }
    Err(EncoderStatus::Failure) => {
      panic!("Failed to encode video");
    }
    Err(EncoderStatus::Encoded) => {}
  }
  Some(frame_summaries)
}

fn write_stats_file<T: Pixel>(ctx: &Context<T>, filename: &Path) -> Result<(), io::Error> {
  let file = File::create(filename)?;
  let writer = BufWriter::new(file);
  serde_json::to_writer(writer, ctx.get_first_pass_data()).expect("Serialization should not fail");
  Ok(())
}

fn do_encode<T: Pixel, D: Decoder>(
  cfg: Config, verbose: bool, mut progress: ProgressInfo,
  output: &mut Muxer,
  source: &mut Source<D>,
  mut y4m_enc: Option<y4m::Encoder<'_, Box<dyn Write>>>
) {
  let mut ctx: Context<T> = cfg.new_context();

  while let Some(frame_info) =
    process_frame(&mut ctx, &mut *output, source, y4m_enc.as_mut())
  {
    for frame in frame_info {
      progress.add_frame(frame);
      if verbose {
        eprintln!("{} - {}", frame, progress);
      } else {
        eprint!("\r{}                    ", progress);
      };
    }

    output.flush().unwrap();
  }

  if cfg.enc.pass == Some(1) {
    if let Err(e) =
      write_stats_file(&ctx, cfg.enc.stats_file.as_ref().unwrap())
    {
      eprintln!("\nError: Failed to write stats file! {}\n", e);
    }
  }
  eprint!("\n{}\n", progress.print_summary());
}

fn main() {
  let mut cli = parse_cli();
  let mut y4m_dec = y4m::decode(&mut cli.io.input).expect("input is not a y4m file");
  let video_info = y4m_dec.get_video_details();
  let y4m_enc = match cli.io.rec.as_mut() {
    Some(rec) => Some(
      y4m::encode(
        video_info.width,
        video_info.height,
        y4m::Ratio::new(video_info.time_base.den as usize, video_info.time_base.num as usize)
      ).with_colorspace(y4m_dec.get_colorspace())
        .write_header(rec)
        .unwrap()
    ),
    None => None
  };

  cli.enc.width = video_info.width;
  cli.enc.height = video_info.height;
  cli.enc.bit_depth = video_info.bit_depth;
  cli.enc.chroma_sampling = video_info.chroma_sampling;
  cli.enc.chroma_sample_position = video_info.chroma_sample_position;
  cli.enc.time_base = video_info.time_base;
  let cfg = Config {
    enc: cli.enc,
    threads: cli.threads,
  };

  eprintln!("{}x{} @ {}/{} fps",
    video_info.width,
    video_info.height,
    video_info.time_base.den,
    video_info.time_base.num
  );

  cli.io.output.write_header(
    video_info.width,
    video_info.height,
    video_info.time_base.den as usize,
    video_info.time_base.num as usize
  );

  let progress = ProgressInfo::new(
    Rational { num: video_info.time_base.den, den: video_info.time_base.num },
    if cli.limit == 0 { None } else { Some(cli.limit) },
      cfg.enc.show_psnr
  );

  for _ in 0..cli.skip {
    y4m_dec.read_frame().expect("Skipped more frames than in the input");
  }

  #[cfg(feature = "signal-hook")]
  let exit_requested = {
    use std::sync::atomic::*;
    let e  = Arc::new(AtomicBool::from(false));

    fn setup_signal(sig: i32, e: Arc<AtomicBool>) {
      unsafe {
        signal_hook::register(sig, move || {
          if e.load(Ordering::SeqCst) {
            std::process::exit(128 + sig);
          }
          e.store(true, Ordering::SeqCst);
          eprintln!("\rExit requested, flushing.\n");
        }).expect("Cannot register the signal hooks");
      }
    }

    setup_signal(signal_hook::SIGTERM, e.clone());
    setup_signal(signal_hook::SIGQUIT, e.clone());
    setup_signal(signal_hook::SIGINT, e.clone());

    e
  };

  #[cfg(feature = "signal-hook")]
  let mut source = Source {
    limit: cli.limit,
    input: y4m_dec,
    count: 0,
    exit_requested
  };
  #[cfg(not(feature = "signal-hook"))]
  let mut source = Source { limit: cli.limit, input: y4m_dec, count: 0 };

  if video_info.bit_depth == 8 {
    do_encode::<u8, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg, cli.verbose, progress, &mut *cli.io.output, &mut source, y4m_enc
    )
  } else {
    do_encode::<u16, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg, cli.verbose, progress, &mut *cli.io.output, &mut source, y4m_enc
    )
  }
}
<commit_msg>Use `dyn` for a dynamic trait<commit_after>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#[macro_use]
extern crate scan_fmt;

mod common;
mod decoder;
mod muxer;
use crate::common::*;
use rav1e::*;

use std::io;
use std::io::Write;
use std::io::Read;
use std::path::Path;
use std::sync::Arc;
use crate::decoder::Decoder;
use crate::decoder::VideoDetails;
use crate::muxer::*;
use std::fs::File;
use std::io::BufWriter;

struct Source<D: Decoder> {
 limit: usize,
 count: usize,
 input: D,
 #[cfg(feature = "signal-hook")]
 exit_requested: Arc<std::sync::atomic::AtomicBool>,
}

impl<D: Decoder> Source<D> {
  fn read_frame<T: Pixel>(&mut self, ctx: &mut Context<T>, video_info: VideoDetails) {
    if self.limit != 0 && self.count == self.limit {
      ctx.flush();
      return;
    }

    #[cfg(feature = "signal-hook")] {
      if self.exit_requested.load(std::sync::atomic::Ordering::SeqCst) {
        ctx.flush();
        return;
      }
    }

    match self.input.read_frame(&video_info) {
      Ok(frame) => {
        match video_info.bit_depth {
          8 | 10 | 12 => {}
          _ => panic!("unknown input bit depth!")
        }
        self.count += 1;
        let _ = ctx.send_frame(Some(Arc::new(frame)));
      }
      _ => {
        ctx.flush();
      }
    };
  }
}

// Encode and write a frame.
// Returns frame information in a `Result`.
fn process_frame<T: Pixel, D: Decoder>(
  ctx: &mut Context<T>, output_file: &mut dyn Muxer,
  source: &mut Source<D>,
  mut y4m_enc: Option<&mut y4m::Encoder<'_, Box<dyn Write>>>
) -> Option<Vec<FrameSummary>> {
  let y4m_details = source.input.get_video_details();
  let mut frame_summaries = Vec::new();
  let pkt_wrapped = ctx.receive_packet();
  match pkt_wrapped {
    Ok(pkt) => {
      output_file.write_frame(pkt.number as u64, pkt.data.as_ref());
      if let (Some(ref mut y4m_enc_uw), Some(ref rec)) = (y4m_enc.as_mut(), &pkt.rec) {
        write_y4m_frame(y4m_enc_uw, rec, y4m_details);
      }
      frame_summaries.push(pkt.into());
    }
    Err(EncoderStatus::NeedMoreData) => {
      source.read_frame(ctx, y4m_details);
    }
    Err(EncoderStatus::EnoughData) => {
      unreachable!();
    }
    Err(EncoderStatus::LimitReached) => {
      return None;
    }
    Err(EncoderStatus::Failure) => {
      panic!("Failed to encode video");
    }
    Err(EncoderStatus::Encoded) => {}
  }
  Some(frame_summaries)
}

fn write_stats_file<T: Pixel>(ctx: &Context<T>, filename: &Path) -> Result<(), io::Error> {
  let file = File::create(filename)?;
  let writer = BufWriter::new(file);
  serde_json::to_writer(writer, ctx.get_first_pass_data()).expect("Serialization should not fail");
  Ok(())
}

fn do_encode<T: Pixel, D: Decoder>(
  cfg: Config, verbose: bool, mut progress: ProgressInfo,
  output: &mut dyn Muxer,
  source: &mut Source<D>,
  mut y4m_enc: Option<y4m::Encoder<'_, Box<dyn Write>>>
) {
  let mut ctx: Context<T> = cfg.new_context();

  while let Some(frame_info) =
    process_frame(&mut ctx, &mut *output, source, y4m_enc.as_mut())
  {
    for frame in frame_info {
      progress.add_frame(frame);
      if verbose {
        eprintln!("{} - {}", frame, progress);
      } else {
        eprint!("\r{}                    ", progress);
      };
    }

    output.flush().unwrap();
  }

  if cfg.enc.pass == Some(1) {
    if let Err(e) =
      write_stats_file(&ctx, cfg.enc.stats_file.as_ref().unwrap())
    {
      eprintln!("\nError: Failed to write stats file! {}\n", e);
    }
  }
  eprint!("\n{}\n", progress.print_summary());
}

fn main() {
  let mut cli = parse_cli();
  let mut y4m_dec = y4m::decode(&mut cli.io.input).expect("input is not a y4m file");
  let video_info = y4m_dec.get_video_details();
  let y4m_enc = match cli.io.rec.as_mut() {
    Some(rec) => Some(
      y4m::encode(
        video_info.width,
        video_info.height,
        y4m::Ratio::new(video_info.time_base.den as usize, video_info.time_base.num as usize)
      ).with_colorspace(y4m_dec.get_colorspace())
        .write_header(rec)
        .unwrap()
    ),
    None => None
  };

  cli.enc.width = video_info.width;
  cli.enc.height = video_info.height;
  cli.enc.bit_depth = video_info.bit_depth;
  cli.enc.chroma_sampling = video_info.chroma_sampling;
  cli.enc.chroma_sample_position = video_info.chroma_sample_position;
  cli.enc.time_base = video_info.time_base;
  let cfg = Config {
    enc: cli.enc,
    threads: cli.threads,
  };

  eprintln!("{}x{} @ {}/{} fps",
    video_info.width,
    video_info.height,
    video_info.time_base.den,
    video_info.time_base.num
  );

  cli.io.output.write_header(
    video_info.width,
    video_info.height,
    video_info.time_base.den as usize,
    video_info.time_base.num as usize
  );

  let progress = ProgressInfo::new(
    Rational { num: video_info.time_base.den, den: video_info.time_base.num },
    if cli.limit == 0 { None } else { Some(cli.limit) },
      cfg.enc.show_psnr
  );

  for _ in 0..cli.skip {
    y4m_dec.read_frame().expect("Skipped more frames than in the input");
  }

  #[cfg(feature = "signal-hook")]
  let exit_requested = {
    use std::sync::atomic::*;
    let e  = Arc::new(AtomicBool::from(false));

    fn setup_signal(sig: i32, e: Arc<AtomicBool>) {
      unsafe {
        signal_hook::register(sig, move || {
          if e.load(Ordering::SeqCst) {
            std::process::exit(128 + sig);
          }
          e.store(true, Ordering::SeqCst);
          eprintln!("\rExit requested, flushing.\n");
        }).expect("Cannot register the signal hooks");
      }
    }

    setup_signal(signal_hook::SIGTERM, e.clone());
    setup_signal(signal_hook::SIGQUIT, e.clone());
    setup_signal(signal_hook::SIGINT, e.clone());

    e
  };

  #[cfg(feature = "signal-hook")]
  let mut source = Source {
    limit: cli.limit,
    input: y4m_dec,
    count: 0,
    exit_requested
  };
  #[cfg(not(feature = "signal-hook"))]
  let mut source = Source { limit: cli.limit, input: y4m_dec, count: 0 };

  if video_info.bit_depth == 8 {
    do_encode::<u8, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg, cli.verbose, progress, &mut *cli.io.output, &mut source, y4m_enc
    )
  } else {
    do_encode::<u16, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg, cli.verbose, progress, &mut *cli.io.output, &mut source, y4m_enc
    )
  }
}
<|endoftext|>


<commit_before>pub struct Choose<T: Clone> {
    vec: Vec<T>,
    k: usize,
    indices: Vec<usize>,
    first: bool,
}

impl<T: Clone> Choose<T> {
    fn new(vec: Vec<T>, k: usize) -> Choose<T> {
        Choose {
            vec: vec,
            k: k,
            indices: (0..k).collect(),
            first: true,
        }
    }

    fn n(&self) -> usize {
        self.vec.len()
    }

    fn from_indices(&self) -> Vec<T> {
        self.indices.iter().map(|&i| self.vec[i].clone()).collect()
    }

    fn increment_indices(&mut self) -> Option<()> {
        let to_increment = (0..self.k)
            .rev()
            .filter(|&i| {
                let max_allowed = self.n() - self.k + i;
                self.indices[i] < max_allowed
            })
            .next();
        let to_increment = match to_increment {
            None => return None,
            Some(i) => i,
        };

        self.indices[to_increment] += 1;

        for j in (to_increment + 1)..self.k {
            let previous_index = self.indices[j - 1];
            self.indices[j] = previous_index + 1;
        }

        Some(())
    }
}

impl<T: Clone> Iterator for Choose<T> {
    type Item = Vec<T>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.n() < self.k {
            return None;
        }

        if !self.first {
            match self.increment_indices() {
                None => return None,
                Some(()) => {}
            };
        };

        self.first = false;

        Some(self.from_indices())
    }
}

pub trait Chooseable<T>
where
    T: Clone,
{
    fn choose(self, k: usize) -> Choose<T>;
}

impl<T> Chooseable<T> for Vec<T>
where
    T: Clone,
{
    fn choose(self, k: usize) -> Choose<T> {
        Choose::new(self, k)
    }
}

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

    #[test]
    fn it_returns_none_when_choosing_one_from_an_empty_list() {
        let vector: Vec<()> = vec![];
        let mut it = vector.choose(1);
        assert_eq!(it.next(), None);
    }

    #[test]
    fn it_returns_the_empty_vector_when_choosing_zero_from_an_empty_list() {
        let vector: Vec<()> = vec![];
        let mut it = vector.choose(0);
        assert_eq!(it.next().unwrap(), vec![]);
        assert_eq!(it.next(), None);
    }

    #[test]
    fn it_returns_the_empty_vector_when_choosing_zero_from_a_list_with_elements() {
        let vector = vec![0, 1, 2];
        let mut it = vector.choose(0);
        assert_eq!(it.next().unwrap().len(), 0);
        assert_eq!(it.next(), None);
    }

    #[test]
    fn it_returns_each_item_when_choosing_one_from_a_list_with_items() {
        let vector = vec![0, 1, 2];
        let mut it = vector.choose(1);

        assert_eq!(it.next().unwrap(), vec![0]);
        assert_eq!(it.next().unwrap(), vec![1]);
        assert_eq!(it.next().unwrap(), vec![2]);
        assert_eq!(it.next(), None);
    }

    #[test]
    fn it_returns_each_item_combination_when_choosing_two_from_a_list_with_items() {
        let vector = vec![0, 1, 2];
        let mut it = vector.choose(2);

        assert_eq!(it.next().unwrap(), vec![0, 1]);
        assert_eq!(it.next().unwrap(), vec![0, 2]);
        assert_eq!(it.next().unwrap(), vec![1, 2]);
        assert_eq!(it.next(), None);
    }

    #[test]
    fn it_returns_each_item_combination_when_choosing_two_from_a_list_with_five_items() {
        let vector = vec![0, 1, 2, 3, 4];
        let mut it = vector.choose(2);

        assert_eq!(it.next().unwrap(), vec![0, 1]);
        assert_eq!(it.next().unwrap(), vec![0, 2]);
        assert_eq!(it.next().unwrap(), vec![0, 3]);
        assert_eq!(it.next().unwrap(), vec![0, 4]);
        assert_eq!(it.next().unwrap(), vec![1, 2]);
        assert_eq!(it.next().unwrap(), vec![1, 3]);
        assert_eq!(it.next().unwrap(), vec![1, 4]);
        assert_eq!(it.next().unwrap(), vec![2, 3]);
        assert_eq!(it.next().unwrap(), vec![2, 4]);
        assert_eq!(it.next().unwrap(), vec![3, 4]);
        assert_eq!(it.next(), None);
    }
}
<commit_msg>return references into the list<commit_after>pub struct Choose<'t, T: 't> {
    list: &'t [T],
    k: usize,
    indices: Vec<usize>,
    first: bool,
}

impl<'t, T> Choose<'t, T> {
    fn new(list: &'t [T], k: usize) -> Choose<'t, T> {
        Choose {
            list: list,
            k: k,
            indices: (0..k).collect(),
            first: true,
        }
    }

    fn n(&self) -> usize {
        self.list.len()
    }

    fn from_indices(&self) -> Vec<&'t T> {
        self.indices.iter().map(|&i| &self.list[i]).collect()
    }

    fn increment_indices(&mut self) -> Option<()> {
        let to_increment = (0..self.k)
            .rev()
            .filter(|&i| {
                let max_allowed = self.n() - self.k + i;
                self.indices[i] < max_allowed
            })
            .next();
        let to_increment = match to_increment {
            None => return None,
            Some(i) => i,
        };

        self.indices[to_increment] += 1;

        for j in (to_increment + 1)..self.k {
            let previous_index = self.indices[j - 1];
            self.indices[j] = previous_index + 1;
        }

        Some(())
    }
}

impl<'t, T> Iterator for Choose<'t, T> {
    type Item = Vec<&'t T>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.n() < self.k {
            return None;
        }

        if !self.first {
            match self.increment_indices() {
                None => return None,
                Some(()) => {}
            };
        };

        self.first = false;

        Some(self.from_indices())
    }
}

pub trait Chooseable<'t, T> {
    fn choose(&'t self, k: usize) -> Choose<'t, T>;
}

impl<'t, T> Chooseable<'t, T> for [T] {
    fn choose(&'t self, k: usize) -> Choose<'t, T> {
        Choose::new(self, k)
    }
}

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

    fn assert_next(it: &mut Choose<usize>, items: Vec<usize>) {
        assert_eq!(it.next().unwrap(), items.iter().collect::<Vec<_>>());
    }

    #[test]
    fn it_returns_none_when_choosing_one_from_an_empty_list() {
        let vector: Vec<()> = vec![];
        let mut it = vector.choose(1);
        assert_eq!(it.next(), None);
    }

    #[test]
    fn it_returns_the_empty_vector_when_choosing_zero_from_an_empty_list() {
        let vector: Vec<usize> = vec![];
        let mut it = vector.choose(0);
        assert_next(&mut it, vec![]);
        assert_eq!(it.next(), None);
    }

    #[test]
    fn it_returns_the_empty_vector_when_choosing_zero_from_a_list_with_elements() {
        let vector = vec![0, 1, 2];
        let mut it = vector.choose(0);
        assert_eq!(it.next().unwrap().len(), 0);
        assert_eq!(it.next(), None);
    }

    #[test]
    fn it_returns_each_item_when_choosing_one_from_a_list_with_items() {
        let vector = vec![0, 1, 2];
        let mut it = vector.choose(1);

        assert_next(&mut it, vec![0]);
        assert_next(&mut it, vec![1]);
        assert_next(&mut it, vec![2]);
        assert_eq!(it.next(), None);
    }

    #[test]
    fn it_returns_each_item_combination_when_choosing_two_from_a_list_with_items() {
        let vector = vec![0, 1, 2];
        let mut it = vector.choose(2);

        assert_next(&mut it, vec![0, 1]);
        assert_next(&mut it, vec![0, 2]);
        assert_next(&mut it, vec![1, 2]);
        assert_eq!(it.next(), None);
    }

    #[test]
    fn it_returns_each_item_combination_when_choosing_two_from_a_list_with_five_items() {
        let vector = vec![0, 1, 2, 3, 4];
        let mut it = vector.choose(2);

        assert_next(&mut it, vec![0, 1]);
        assert_next(&mut it, vec![0, 2]);
        assert_next(&mut it, vec![0, 3]);
        assert_next(&mut it, vec![0, 4]);
        assert_next(&mut it, vec![1, 2]);
        assert_next(&mut it, vec![1, 3]);
        assert_next(&mut it, vec![1, 4]);
        assert_next(&mut it, vec![2, 3]);
        assert_next(&mut it, vec![2, 4]);
        assert_next(&mut it, vec![3, 4]);
        assert_eq!(it.next(), None);
    }
}
<|endoftext|>


<commit_before><commit_msg>openssl: port to new ContextBuilder API<commit_after><|endoftext|>