<commit_before>use std::cmp::max;

use codec::{
    common::{eyre::Result, itertools::Itertools},
    stencila_schema::*,
    EncodeOptions,
};

/// Encode a `Node` to Markdown
pub fn encode(node: &Node, _options: Option<EncodeOptions>) -> Result<String> {
    Ok(node.to_md().trim().to_string())
}

/// A trait to encode a `Node` as Markdown
pub trait ToMd {
    fn to_md(&self) -> String;
}

macro_rules! primitive_to_md {
    ($type:ty) => {
        impl ToMd for $type {
            fn to_md(&self) -> String {
                self.to_string()
            }
        }
    };
}

primitive_to_md!(Null);
primitive_to_md!(Boolean);
primitive_to_md!(Integer);
primitive_to_md!(Number);
primitive_to_md!(String);

impl<Type> ToMd for Option<Type>
where
    Type: ToMd,
{
    fn to_md(&self) -> String {
        match self {
            Some(value) => value.to_md(),
            None => "".to_string(),
        }
    }
}

impl<Type> ToMd for Box<Type>
where
    Type: ToMd,
{
    fn to_md(&self) -> String {
        self.as_ref().to_md()
    }
}

impl<Type> ToMd for Vec<Type>
where
    Type: ToMd,
{
    fn to_md(&self) -> String {
        self.iter()
            .map(|item| item.to_md())
            .collect::<Vec<String>>()
            .concat()
    }
}

macro_rules! slice_to_md {
    ($type:ty) => {
        impl ToMd for $type {
            fn to_md(&self) -> String {
                self.iter()
                    .map(|item| item.to_md())
                    .collect::<Vec<String>>()
                    .concat()
            }
        }
    };
}
slice_to_md!([Node]);
slice_to_md!([InlineContent]);
slice_to_md!([BlockContent]);

macro_rules! delimited_inline_content_to_md {
    ($type:ty, $delimiter:expr) => {
        impl ToMd for $type {
            fn to_md(&self) -> String {
                [$delimiter, &self.content.to_md(), $delimiter].concat()
            }
        }
    };
}

delimited_inline_content_to_md!(Delete, "~~");
delimited_inline_content_to_md!(Emphasis, "_");
delimited_inline_content_to_md!(Strong, "**");
delimited_inline_content_to_md!(Subscript, "~");
delimited_inline_content_to_md!(Superscript, "^");

impl ToMd for NontextualAnnotation {
    fn to_md(&self) -> String {
        ["", &self.content.to_md(), ""].concat()
    }
}

impl ToMd for Quote {
    fn to_md(&self) -> String {
        ["<q>", &self.content.to_md(), "</q>"].concat()
    }
}

impl ToMd for CodeExpression {
    fn to_md(&self) -> String {
        ["`", &self.text, "`{", &self.programming_language, " exec}"].concat()
    }
}

macro_rules! delimited_inline_text_to_md {
    ($type:ty, $delimiter:expr) => {
        impl ToMd for $type {
            fn to_md(&self) -> String {
                [$delimiter, &self.text, $delimiter].concat()
            }
        }
    };
}

delimited_inline_text_to_md!(CodeFragment, "`");
delimited_inline_text_to_md!(MathFragment, "$");

impl ToMd for Link {
    fn to_md(&self) -> String {
        ["[", &self.content.to_md(), "](", &self.target, ")"].concat()
    }
}

macro_rules! inline_media_object_to_md {
    ($type:ty) => {
        impl ToMd for $type {
            fn to_md(&self) -> String {
                ["![", "](", &self.content_url, ")"].concat()
            }
        }
    };
}

inline_media_object_to_md!(AudioObjectSimple);
inline_media_object_to_md!(ImageObjectSimple);
inline_media_object_to_md!(VideoObjectSimple);

impl ToMd for Heading {
    fn to_md(&self) -> String {
        [
            &"#".repeat(self.depth.unwrap_or(1) as usize),
            " ",
            &self.content.to_md(),
            "\n\n",
        ]
        .concat()
    }
}

impl ToMd for Paragraph {
    fn to_md(&self) -> String {
        [&self.content.to_md(), "\n\n"].concat()
    }
}

impl ToMd for CodeBlock {
    fn to_md(&self) -> String {
        let lang = match &self.programming_language {
            Some(boxed) => boxed.as_str(),
            None => "",
        };

        ["```", lang, "\n", &self.text, "\n```\n\n"].concat()
    }
}

impl ToMd for CodeChunk {
    fn to_md(&self) -> String {
        [
            "```",
            &self.programming_language,
            " exec \n",
            &self.text,
            "\n```\n\n",
        ]
        .concat()
    }
}

impl ToMd for List {
    fn to_md(&self) -> String {
        let ordered = matches!(&self.order, Some(ListOrder::Ascending));
        let items: Vec<String> = self
            .items
            .iter()
            .enumerate()
            .map(|(index, item)| {
                let bullet = if ordered {
                    (index + 1).to_string() + ". "
                } else {
                    "- ".to_string()
                };
                item.to_md()
                    .split('\n')
                    .enumerate()
                    .map(|(index, line)| {
                        if index == 0 {
                            [bullet.clone(), line.to_string()].concat()
                        } else if line.trim().is_empty() {
                            String::new()
                        } else {
                            ["  ", line].concat()
                        }
                    })
                    .join("\n")
            })
            .collect();

        // Keep lists tight if no items have internal newlines
        let mut tight = true;
        for item in &items {
            if item.trim().contains('\n') {
                tight = false;
                break;
            }
        }
        let items = items
            .iter()
            .map(|item| item.trim())
            .join(if tight { "\n" } else { "\n\n" });

        [items, "\n\n".to_string()].concat()
    }
}

impl ToMd for ListItem {
    fn to_md(&self) -> String {
        let checkbox = self.is_checked.map(|is_checked| match is_checked {
            true => InlineContent::String("[x] ".to_string()),
            false => InlineContent::String("[ ] ".to_string()),
        });
        match &self.content {
            Some(content) => match content {
                ListItemContent::VecInlineContent(inlines) => match checkbox {
                    Some(checkbox) => [vec![checkbox], inlines.clone()].concat().to_md(),
                    None => inlines.to_md(),
                },
                ListItemContent::VecBlockContent(blocks) => match checkbox {
                    Some(checkbox) => {
                        // Check box is only added is the first block is a paragraph
                        if let Some(BlockContent::Paragraph(paragraph)) = blocks.first() {
                            let mut paragraph = paragraph.clone();
                            paragraph.content.insert(0, checkbox);
                            [paragraph.to_md(), blocks[1..].to_md()].concat()
                        } else {
                            blocks.to_md()
                        }
                    }
                    None => blocks.to_md(),
                },
            },
            None => "".to_string(),
        }
    }
}

impl ToMd for QuoteBlock {
    fn to_md(&self) -> String {
        let content: Vec<String> = self
            .content
            .iter()
            .map(|block| {
                block
                    .to_md()
                    .split('\n')
                    .map(|line| ["> ", line].concat())
                    .join("\n")
            })
            .collect();
        [content.join("\n"), "\n\n".to_string()].concat()
    }
}

impl ToMd for TableSimple {
    fn to_md(&self) -> String {
        let mut column_widths: Vec<usize> = Vec::new();
        let mut rows: Vec<Vec<String>> = Vec::new();
        for row in &self.rows {
            let mut cells: Vec<String> = Vec::new();
            for (column, cell) in row.cells.iter().enumerate() {
                let content = match &cell.content {
                    None => "".to_string(),
                    Some(content) => match content {
                        TableCellContent::VecInlineContent(inlines) => inlines.to_md(),
                        TableCellContent::VecBlockContent(blocks) => blocks.to_md(),
                    },
                };
                let width = content.len();
                match column_widths.get_mut(column) {
                    Some(column_width) => {
                        if width > *column_width {
                            *column_width = width
                        }
                    }
                    None => column_widths.push(max(3, width)),
                }
                cells.push(content);
            }
            rows.push(cells);
        }

        let row_to_md = |cells: &[String]| -> String {
            cells
                .iter()
                .enumerate()
                .map(|(column, content)| {
                    format!("{:width$}", content, width = column_widths[column])
                })
                .join(" | ")
        };

        let (first, rest) = if rows.len() == 1 {
            (
                row_to_md(&vec!["".to_string(); column_widths.len()]),
                row_to_md(&rows[0]),
            )
        } else {
            (
                row_to_md(&rows[0]),
                rows[1..].iter().map(|row| row_to_md(row)).join(" |\n| "),
            )
        };

        let dashes = column_widths
            .iter()
            .map(|width| "-".repeat(*width))
            .join(" | ");

        [
            "| ", &first, " |\n", "| ", &dashes, " |\n", "| ", &rest, " |\n\n",
        ]
        .concat()
    }
}

impl ToMd for ThematicBreak {
    fn to_md(&self) -> String {
        "---\n\n".to_string()
    }
}

macro_rules! content_to_md {
    ($type:ty) => {
        impl ToMd for $type {
            fn to_md(&self) -> String {
                self.content.to_md()
            }
        }
    };
}

content_to_md!(Article);
content_to_md!(CreativeWork);

impl ToMd for CreativeWorkContent {
    fn to_md(&self) -> String {
        match self {
            CreativeWorkContent::String(node) => node.to_md(),
            CreativeWorkContent::VecNode(nodes) => nodes.to_md(),
        }
    }
}

impl ToMd for Node {
    fn to_md(&self) -> String {
        match self {
            Node::Article(node) => node.to_md(),
            Node::Boolean(node) => node.to_md(),
            //Node::Cite(node) => node.to_md(),
            Node::CodeBlock(node) => node.to_md(),
            Node::CodeFragment(node) => node.to_md(),
            Node::CreativeWork(node) => node.to_md(),
            Node::Delete(node) => node.to_md(),
            Node::Emphasis(node) => node.to_md(),
            Node::Heading(node) => node.to_md(),
            Node::Integer(node) => node.to_md(),
            Node::Link(node) => node.to_md(),
            Node::List(node) => node.to_md(),
            Node::NontextualAnnotation(node) => node.to_md(),
            //Node::Note(node) => node.to_md(),
            Node::Null(node) => node.to_md(),
            Node::Number(node) => node.to_md(),
            Node::Paragraph(node) => node.to_md(),
            Node::Quote(node) => node.to_md(),
            Node::QuoteBlock(node) => node.to_md(),
            Node::String(node) => node.to_md(),
            Node::Strong(node) => node.to_md(),
            Node::Subscript(node) => node.to_md(),
            Node::Superscript(node) => node.to_md(),
            _ => "".to_string(),
        }
    }
}

impl ToMd for InlineContent {
    fn to_md(&self) -> String {
        match self {
            InlineContent::AudioObject(node) => node.to_md(),
            InlineContent::Boolean(node) => node.to_md(),
            //InlineContent::Cite(node) => node.to_md(),
            InlineContent::CodeExpression(node) => node.to_md(),
            InlineContent::CodeFragment(node) => node.to_md(),
            InlineContent::Delete(node) => node.to_md(),
            InlineContent::Emphasis(node) => node.to_md(),
            InlineContent::ImageObject(node) => node.to_md(),
            InlineContent::Integer(node) => node.to_md(),
            InlineContent::Link(node) => node.to_md(),
            InlineContent::NontextualAnnotation(node) => node.to_md(),
            //InlineContent::Note(node) => node.to_md(),
            InlineContent::Null(node) => node.to_md(),
            InlineContent::Number(node) => node.to_md(),
            InlineContent::MathFragment(node) => node.to_md(),
            InlineContent::Quote(node) => node.to_md(),
            InlineContent::String(node) => node.to_md(),
            InlineContent::Strong(node) => node.to_md(),
            InlineContent::Subscript(node) => node.to_md(),
            InlineContent::Superscript(node) => node.to_md(),
            InlineContent::VideoObject(node) => node.to_md(),
            _ => "".to_string(),
        }
    }
}

impl ToMd for BlockContent {
    fn to_md(&self) -> String {
        match self {
            //BlockContent::Claim(node) => node.to_md(),
            BlockContent::CodeBlock(node) => node.to_md(),
            BlockContent::CodeChunk(node) => node.to_md(),
            BlockContent::Heading(node) => node.to_md(),
            BlockContent::List(node) => node.to_md(),
            //BlockContent::MathBlock(node) => node.to_md(),
            BlockContent::Paragraph(node) => node.to_md(),
            BlockContent::QuoteBlock(node) => node.to_md(),
            BlockContent::Table(node) => node.to_md(),
            BlockContent::ThematicBreak(node) => node.to_md(),
            _ => "".to_string(),
        }
    }
}

impl ToMd for ThingDescription {
    fn to_md(&self) -> String {
        match self {
            ThingDescription::String(string) => string.to_string(),
            ThingDescription::VecInlineContent(inlines) => inlines.to_md(),
            ThingDescription::VecBlockContent(blocks) => blocks.to_md(),
        }
    }
}
<commit_msg>fix(Markdown codec): Ensure table cells have no newlines<commit_after>use std::cmp::max;

use codec::{
    common::{eyre::Result, itertools::Itertools},
    stencila_schema::*,
    EncodeOptions,
};

/// Encode a `Node` to Markdown
pub fn encode(node: &Node, _options: Option<EncodeOptions>) -> Result<String> {
    Ok(node.to_md().trim().to_string())
}

/// A trait to encode a `Node` as Markdown
pub trait ToMd {
    fn to_md(&self) -> String;
}

macro_rules! primitive_to_md {
    ($type:ty) => {
        impl ToMd for $type {
            fn to_md(&self) -> String {
                self.to_string()
            }
        }
    };
}

primitive_to_md!(Null);
primitive_to_md!(Boolean);
primitive_to_md!(Integer);
primitive_to_md!(Number);
primitive_to_md!(String);

impl<Type> ToMd for Option<Type>
where
    Type: ToMd,
{
    fn to_md(&self) -> String {
        match self {
            Some(value) => value.to_md(),
            None => "".to_string(),
        }
    }
}

impl<Type> ToMd for Box<Type>
where
    Type: ToMd,
{
    fn to_md(&self) -> String {
        self.as_ref().to_md()
    }
}

impl<Type> ToMd for Vec<Type>
where
    Type: ToMd,
{
    fn to_md(&self) -> String {
        self.iter()
            .map(|item| item.to_md())
            .collect::<Vec<String>>()
            .concat()
    }
}

macro_rules! slice_to_md {
    ($type:ty) => {
        impl ToMd for $type {
            fn to_md(&self) -> String {
                self.iter()
                    .map(|item| item.to_md())
                    .collect::<Vec<String>>()
                    .concat()
            }
        }
    };
}
slice_to_md!([Node]);
slice_to_md!([InlineContent]);
slice_to_md!([BlockContent]);

macro_rules! delimited_inline_content_to_md {
    ($type:ty, $delimiter:expr) => {
        impl ToMd for $type {
            fn to_md(&self) -> String {
                [$delimiter, &self.content.to_md(), $delimiter].concat()
            }
        }
    };
}

delimited_inline_content_to_md!(Delete, "~~");
delimited_inline_content_to_md!(Emphasis, "_");
delimited_inline_content_to_md!(Strong, "**");
delimited_inline_content_to_md!(Subscript, "~");
delimited_inline_content_to_md!(Superscript, "^");

impl ToMd for NontextualAnnotation {
    fn to_md(&self) -> String {
        ["", &self.content.to_md(), ""].concat()
    }
}

impl ToMd for Quote {
    fn to_md(&self) -> String {
        ["<q>", &self.content.to_md(), "</q>"].concat()
    }
}

impl ToMd for CodeExpression {
    fn to_md(&self) -> String {
        ["`", &self.text, "`{", &self.programming_language, " exec}"].concat()
    }
}

macro_rules! delimited_inline_text_to_md {
    ($type:ty, $delimiter:expr) => {
        impl ToMd for $type {
            fn to_md(&self) -> String {
                [$delimiter, &self.text, $delimiter].concat()
            }
        }
    };
}

delimited_inline_text_to_md!(CodeFragment, "`");
delimited_inline_text_to_md!(MathFragment, "$");

impl ToMd for Link {
    fn to_md(&self) -> String {
        ["[", &self.content.to_md(), "](", &self.target, ")"].concat()
    }
}

macro_rules! inline_media_object_to_md {
    ($type:ty) => {
        impl ToMd for $type {
            fn to_md(&self) -> String {
                ["![", "](", &self.content_url, ")"].concat()
            }
        }
    };
}

inline_media_object_to_md!(AudioObjectSimple);
inline_media_object_to_md!(ImageObjectSimple);
inline_media_object_to_md!(VideoObjectSimple);

impl ToMd for Heading {
    fn to_md(&self) -> String {
        [
            &"#".repeat(self.depth.unwrap_or(1) as usize),
            " ",
            &self.content.to_md(),
            "\n\n",
        ]
        .concat()
    }
}

impl ToMd for Paragraph {
    fn to_md(&self) -> String {
        [&self.content.to_md(), "\n\n"].concat()
    }
}

impl ToMd for CodeBlock {
    fn to_md(&self) -> String {
        let lang = match &self.programming_language {
            Some(boxed) => boxed.as_str(),
            None => "",
        };

        ["```", lang, "\n", &self.text, "\n```\n\n"].concat()
    }
}

impl ToMd for CodeChunk {
    fn to_md(&self) -> String {
        [
            "```",
            &self.programming_language,
            " exec \n",
            &self.text,
            "\n```\n\n",
        ]
        .concat()
    }
}

impl ToMd for List {
    fn to_md(&self) -> String {
        let ordered = matches!(&self.order, Some(ListOrder::Ascending));
        let items: Vec<String> = self
            .items
            .iter()
            .enumerate()
            .map(|(index, item)| {
                let bullet = if ordered {
                    (index + 1).to_string() + ". "
                } else {
                    "- ".to_string()
                };
                item.to_md()
                    .split('\n')
                    .enumerate()
                    .map(|(index, line)| {
                        if index == 0 {
                            [bullet.clone(), line.to_string()].concat()
                        } else if line.trim().is_empty() {
                            String::new()
                        } else {
                            ["  ", line].concat()
                        }
                    })
                    .join("\n")
            })
            .collect();

        // Keep lists tight if no items have internal newlines
        let mut tight = true;
        for item in &items {
            if item.trim().contains('\n') {
                tight = false;
                break;
            }
        }
        let items = items
            .iter()
            .map(|item| item.trim())
            .join(if tight { "\n" } else { "\n\n" });

        [items, "\n\n".to_string()].concat()
    }
}

impl ToMd for ListItem {
    fn to_md(&self) -> String {
        let checkbox = self.is_checked.map(|is_checked| match is_checked {
            true => InlineContent::String("[x] ".to_string()),
            false => InlineContent::String("[ ] ".to_string()),
        });
        match &self.content {
            Some(content) => match content {
                ListItemContent::VecInlineContent(inlines) => match checkbox {
                    Some(checkbox) => [vec![checkbox], inlines.clone()].concat().to_md(),
                    None => inlines.to_md(),
                },
                ListItemContent::VecBlockContent(blocks) => match checkbox {
                    Some(checkbox) => {
                        // Check box is only added is the first block is a paragraph
                        if let Some(BlockContent::Paragraph(paragraph)) = blocks.first() {
                            let mut paragraph = paragraph.clone();
                            paragraph.content.insert(0, checkbox);
                            [paragraph.to_md(), blocks[1..].to_md()].concat()
                        } else {
                            blocks.to_md()
                        }
                    }
                    None => blocks.to_md(),
                },
            },
            None => "".to_string(),
        }
    }
}

impl ToMd for QuoteBlock {
    fn to_md(&self) -> String {
        let content: Vec<String> = self
            .content
            .iter()
            .map(|block| {
                block
                    .to_md()
                    .split('\n')
                    .map(|line| ["> ", line].concat())
                    .join("\n")
            })
            .collect();
        [content.join("\n"), "\n\n".to_string()].concat()
    }
}

impl ToMd for TableSimple {
    fn to_md(&self) -> String {
        let mut column_widths: Vec<usize> = Vec::new();
        let mut rows: Vec<Vec<String>> = Vec::new();
        for row in &self.rows {
            let mut cells: Vec<String> = Vec::new();
            for (column, cell) in row.cells.iter().enumerate() {
                let content = match &cell.content {
                    None => "".to_string(),
                    Some(content) => match content {
                        TableCellContent::VecInlineContent(inlines) => inlines.to_md(),
                        TableCellContent::VecBlockContent(blocks) => blocks.to_md(),
                    },
                };
                let width = content.len();
                match column_widths.get_mut(column) {
                    Some(column_width) => {
                        if width > *column_width {
                            *column_width = width
                        }
                    }
                    None => column_widths.push(max(3, width)),
                }
                cells.push(content);
            }
            rows.push(cells);
        }

        let row_to_md = |cells: &[String]| -> String {
            cells
                .iter()
                .enumerate()
                .map(|(column, content)| {
                    format!(
                        "{:width$}",
                        // Ensure cell has no newlines which will break table
                        content.replace("\r\n", " ").replace('\n', " "),
                        width = column_widths[column]
                    )
                })
                .join(" | ")
        };

        let (first, rest) = if rows.len() == 1 {
            (
                row_to_md(&vec!["".to_string(); column_widths.len()]),
                row_to_md(&rows[0]),
            )
        } else {
            (
                row_to_md(&rows[0]),
                rows[1..].iter().map(|row| row_to_md(row)).join(" |\n| "),
            )
        };

        let dashes = column_widths
            .iter()
            .map(|width| "-".repeat(*width))
            .join(" | ");

        [
            "| ", &first, " |\n", "| ", &dashes, " |\n", "| ", &rest, " |\n\n",
        ]
        .concat()
    }
}

impl ToMd for ThematicBreak {
    fn to_md(&self) -> String {
        "---\n\n".to_string()
    }
}

macro_rules! content_to_md {
    ($type:ty) => {
        impl ToMd for $type {
            fn to_md(&self) -> String {
                self.content.to_md()
            }
        }
    };
}

content_to_md!(Article);
content_to_md!(CreativeWork);

impl ToMd for CreativeWorkContent {
    fn to_md(&self) -> String {
        match self {
            CreativeWorkContent::String(node) => node.to_md(),
            CreativeWorkContent::VecNode(nodes) => nodes.to_md(),
        }
    }
}

impl ToMd for Node {
    fn to_md(&self) -> String {
        match self {
            Node::Article(node) => node.to_md(),
            Node::Boolean(node) => node.to_md(),
            //Node::Cite(node) => node.to_md(),
            Node::CodeBlock(node) => node.to_md(),
            Node::CodeFragment(node) => node.to_md(),
            Node::CreativeWork(node) => node.to_md(),
            Node::Delete(node) => node.to_md(),
            Node::Emphasis(node) => node.to_md(),
            Node::Heading(node) => node.to_md(),
            Node::Integer(node) => node.to_md(),
            Node::Link(node) => node.to_md(),
            Node::List(node) => node.to_md(),
            Node::NontextualAnnotation(node) => node.to_md(),
            //Node::Note(node) => node.to_md(),
            Node::Null(node) => node.to_md(),
            Node::Number(node) => node.to_md(),
            Node::Paragraph(node) => node.to_md(),
            Node::Quote(node) => node.to_md(),
            Node::QuoteBlock(node) => node.to_md(),
            Node::String(node) => node.to_md(),
            Node::Strong(node) => node.to_md(),
            Node::Subscript(node) => node.to_md(),
            Node::Superscript(node) => node.to_md(),
            _ => "".to_string(),
        }
    }
}

impl ToMd for InlineContent {
    fn to_md(&self) -> String {
        match self {
            InlineContent::AudioObject(node) => node.to_md(),
            InlineContent::Boolean(node) => node.to_md(),
            //InlineContent::Cite(node) => node.to_md(),
            InlineContent::CodeExpression(node) => node.to_md(),
            InlineContent::CodeFragment(node) => node.to_md(),
            InlineContent::Delete(node) => node.to_md(),
            InlineContent::Emphasis(node) => node.to_md(),
            InlineContent::ImageObject(node) => node.to_md(),
            InlineContent::Integer(node) => node.to_md(),
            InlineContent::Link(node) => node.to_md(),
            InlineContent::NontextualAnnotation(node) => node.to_md(),
            //InlineContent::Note(node) => node.to_md(),
            InlineContent::Null(node) => node.to_md(),
            InlineContent::Number(node) => node.to_md(),
            InlineContent::MathFragment(node) => node.to_md(),
            InlineContent::Quote(node) => node.to_md(),
            InlineContent::String(node) => node.to_md(),
            InlineContent::Strong(node) => node.to_md(),
            InlineContent::Subscript(node) => node.to_md(),
            InlineContent::Superscript(node) => node.to_md(),
            InlineContent::VideoObject(node) => node.to_md(),
            _ => "".to_string(),
        }
    }
}

impl ToMd for BlockContent {
    fn to_md(&self) -> String {
        match self {
            //BlockContent::Claim(node) => node.to_md(),
            BlockContent::CodeBlock(node) => node.to_md(),
            BlockContent::CodeChunk(node) => node.to_md(),
            BlockContent::Heading(node) => node.to_md(),
            BlockContent::List(node) => node.to_md(),
            //BlockContent::MathBlock(node) => node.to_md(),
            BlockContent::Paragraph(node) => node.to_md(),
            BlockContent::QuoteBlock(node) => node.to_md(),
            BlockContent::Table(node) => node.to_md(),
            BlockContent::ThematicBreak(node) => node.to_md(),
            _ => "".to_string(),
        }
    }
}

impl ToMd for ThingDescription {
    fn to_md(&self) -> String {
        match self {
            ThingDescription::String(string) => string.to_string(),
            ThingDescription::VecInlineContent(inlines) => inlines.to_md(),
            ThingDescription::VecBlockContent(blocks) => blocks.to_md(),
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

mod intmap;
mod stringmap;

use intmap::int_to_int;
use stringmap::int_to_string;

fn main() {
    int_to_int();
    int_to_string();
}
<commit_msg>Tweak import.<commit_after>mod intmap;
mod stringmap;

use intmap::*;
use stringmap::*;

fn main() {
    int_to_int();
    int_to_string();
}
<|endoftext|>


<commit_before>#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
enum Token {
    Mine = b'*',
    Empty = b' ',
}

impl Into<char> for Token {
    fn into(self) -> char {
        self as u8 as char
    }
}

impl Token {
    fn from(c: char) -> Result<Token, ()> {
        match c {
            '*' => Ok(Token::Mine),
            ' ' => Ok(Token::Empty),
            _ => Err(()),
        }
    }
}

struct Board {
    field: Vec<Vec<Token>>,
}

impl Board {
    fn new(minefield: &[&str]) -> Self {
        let field = minefield
            .iter()
            .map(|row| row.chars().map(|char| Token::from(char).unwrap()).collect())
            .collect();
        Board { field }
    }

    fn annotated(&self) -> Vec<String> {
        let mut annotated: Vec<String> = Vec::new();

        for (y, row) in self.field.iter().enumerate() {
            let mut annotated_row = String::new();
            for (x, token) in row.iter().enumerate() {
                match token {
                    Token::Mine => annotated_row.push(Token::Mine.into()),
                    Token::Empty => {
                        let neighbor_mines = self.num_neighbor_mines(y as u32, x as u32);
                        let annotated_location = if neighbor_mines == 0 {
                            " ".to_string()
                        } else {
                            neighbor_mines.to_string()
                        };
                        annotated_row.push_str(&annotated_location)
                    }
                }
            }
            annotated.push(annotated_row)
        }

        annotated
    }

    fn num_neighbor_mines(&self, y: u32, x: u32) -> usize {
        return self
            .get_neighbors(y, x)
            .iter()
            .filter(|neighbor| neighbor == &&&Token::Mine)
            .count();
    }

    fn get_neighbors(&self, y: u32, x: u32) -> Vec<&Token> {
        let mut neighbors = Vec::new();
        let y = y as i32;
        let x = x as i32;

        let delta_ys: Vec<i32> = (-1..=1).collect();
        for delta_y in delta_ys {
            let delta_xs: Vec<i32> = (-1..=1).collect();
            for delta_x in delta_xs {
                if delta_y == 0 && delta_x == 0 {
                    continue;
                }
                if y + delta_y < 0 || y + delta_y >= self.num_rows() as i32 {
                    continue;
                }
                if x + delta_x < 0 || x + delta_x >= self.num_cols() as i32 {
                    continue;
                }
                let neighbor = &self.field[(y + delta_y) as usize][(x + delta_x) as usize];
                neighbors.push(neighbor)
            }
        }

        neighbors
    }

    fn num_rows(&self) -> usize {
        return self.field.len();
    }

    fn num_cols(&self) -> usize {
        return self.field[0].len();
    }
}

pub fn annotate(minefield: &[&str]) -> Vec<String> {
    let board = Board::new(minefield);
    return board.annotated();
}
<commit_msg>Extract annotate_row<commit_after>#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
enum Token {
    Mine = b'*',
    Empty = b' ',
}

impl Into<char> for Token {
    fn into(self) -> char {
        self as u8 as char
    }
}

impl Token {
    fn from(c: char) -> Result<Token, ()> {
        match c {
            '*' => Ok(Token::Mine),
            ' ' => Ok(Token::Empty),
            _ => Err(()),
        }
    }
}

struct Board {
    field: Vec<Vec<Token>>,
}

impl Board {
    fn new(minefield: &[&str]) -> Self {
        let field = minefield
            .iter()
            .map(|row| row.chars().map(|char| Token::from(char).unwrap()).collect())
            .collect();
        Board { field }
    }

    fn annotate(&self) -> Vec<String> {
        let mut annotated: Vec<String> = Vec::new();

        for (y, _) in self.field.iter().enumerate() {
            annotated.push(self.annotate_row(y));
        }

        annotated
    }

    fn annotate_row(&self, y: usize) -> String {
        let mut annotated_row = String::new();

        let row = &self.field[y];
        for (x, token) in row.iter().enumerate() {
            match token {
                Token::Mine => annotated_row.push(Token::Mine.into()),
                Token::Empty => {
                    let neighbor_mines = self.num_neighbor_mines(y as u32, x as u32);
                    let annotated_location = if neighbor_mines == 0 {
                        " ".to_string()
                    } else {
                        neighbor_mines.to_string()
                    };
                    annotated_row.push_str(&annotated_location)
                }
            }
        }
        annotated_row
    }

    fn num_neighbor_mines(&self, y: u32, x: u32) -> usize {
        return self
            .get_neighbors(y, x)
            .iter()
            .filter(|neighbor| neighbor == &&&Token::Mine)
            .count();
    }

    fn get_neighbors(&self, y: u32, x: u32) -> Vec<&Token> {
        let mut neighbors = Vec::new();
        let y = y as i32;
        let x = x as i32;

        let delta_ys: Vec<i32> = (-1..=1).collect();
        for delta_y in delta_ys {
            let delta_xs: Vec<i32> = (-1..=1).collect();
            for delta_x in delta_xs {
                if delta_y == 0 && delta_x == 0 {
                    continue;
                }
                if y + delta_y < 0 || y + delta_y >= self.num_rows() as i32 {
                    continue;
                }
                if x + delta_x < 0 || x + delta_x >= self.num_cols() as i32 {
                    continue;
                }
                let neighbor = &self.field[(y + delta_y) as usize][(x + delta_x) as usize];
                neighbors.push(neighbor)
            }
        }

        neighbors
    }

    fn num_rows(&self) -> usize {
        return self.field.len();
    }

    fn num_cols(&self) -> usize {
        return self.field[0].len();
    }
}

pub fn annotate(minefield: &[&str]) -> Vec<String> {
    let board = Board::new(minefield);
    return board.annotate();
}
<|endoftext|>


<commit_before>extern crate cargotest;
extern crate hamcrest;

use std::fs::{self, File};
use std::io::prelude::*;

use cargotest::sleep_ms;
use cargotest::support::{project, execs, path2url};
use cargotest::support::paths::CargoPathExt;
use hamcrest::{assert_that, existing_file};

#[test]
fn modifying_and_moving() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.1"
        "#)
        .file("src/main.rs", r#"
            mod a; fn main() {}
        "#)
        .file("src/a.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0).with_stderr(format!("\
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", dir = path2url(p.root()))));

    assert_that(p.cargo("build"),
                execs().with_status(0).with_stdout(""));
    p.root().move_into_the_past();
    p.root().join("target").move_into_the_past();

    File::create(&p.root().join("src/a.rs")).unwrap()
         .write_all(b"#[allow(unused)]fn main() {}").unwrap();
    assert_that(p.cargo("build"),
                execs().with_status(0).with_stderr(format!("\
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", dir = path2url(p.root()))));

    fs::rename(&p.root().join("src/a.rs"), &p.root().join("src/b.rs")).unwrap();
    assert_that(p.cargo("build"),
                execs().with_status(101));
}

#[test]
fn modify_only_some_files() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.1"
        "#)
        .file("src/lib.rs", "mod a;")
        .file("src/a.rs", "")
        .file("src/main.rs", r#"
            mod b;
            fn main() {}
        "#)
        .file("src/b.rs", "")
        .file("tests/test.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0).with_stderr(format!("\
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", dir = path2url(p.root()))));
    assert_that(p.cargo("test"),
                execs().with_status(0));
    sleep_ms(1000);

    assert_that(&p.bin("foo"), existing_file());

    let lib = p.root().join("src/lib.rs");
    let bin = p.root().join("src/b.rs");

    File::create(&lib).unwrap().write_all(b"invalid rust code").unwrap();
    File::create(&bin).unwrap().write_all(b"#[allow(unused)]fn foo() {}").unwrap();
    lib.move_into_the_past();

    // Make sure the binary is rebuilt, not the lib
    assert_that(p.cargo("build"),
                execs().with_status(0).with_stderr(format!("\
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", dir = path2url(p.root()))));
    assert_that(&p.bin("foo"), existing_file());
}

#[test]
fn rebuild_sub_package_then_while_package() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.1"

            [dependencies.a]
            path = "a"
            [dependencies.b]
            path = "b"
        "#)
        .file("src/lib.rs", "extern crate a; extern crate b;")
        .file("a/Cargo.toml", r#"
            [package]
            name = "a"
            authors = []
            version = "0.0.1"
            [dependencies.b]
            path = "../b"
        "#)
        .file("a/src/lib.rs", "extern crate b;")
        .file("b/Cargo.toml", r#"
            [package]
            name = "b"
            authors = []
            version = "0.0.1"
        "#)
        .file("b/src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0));

    File::create(&p.root().join("b/src/lib.rs")).unwrap().write_all(br#"
        pub fn b() {}
    "#).unwrap();

    assert_that(p.cargo("build").arg("-pb"),
                execs().with_status(0));

    File::create(&p.root().join("src/lib.rs")).unwrap().write_all(br#"
        extern crate a;
        extern crate b;
        pub fn toplevel() {}
    "#).unwrap();

    assert_that(p.cargo("build"),
                execs().with_status(0));
}

#[test]
fn changing_features_is_ok() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.1"

            [features]
            foo = []
        "#)
        .file("src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0)
                       .with_stderr("\
[..]Compiling foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));

    assert_that(p.cargo("build").arg("--features").arg("foo"),
                execs().with_status(0)
                       .with_stderr("\
[..]Compiling foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));

    assert_that(p.cargo("build"),
                execs().with_status(0)
                       .with_stderr("\
[..]Compiling foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));

    assert_that(p.cargo("build"),
                execs().with_status(0)
                       .with_stdout(""));
}

#[test]
fn rebuild_tests_if_lib_changes() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []
        "#)
        .file("src/lib.rs", "pub fn foo() {}")
        .file("tests/foo.rs", r#"
            extern crate foo;
            #[test]
            fn test() { foo::foo(); }
        "#);

    assert_that(p.cargo_process("build"),
                execs().with_status(0));
    assert_that(p.cargo("test"),
                execs().with_status(0));

    File::create(&p.root().join("src/lib.rs")).unwrap();
    p.root().move_into_the_past();
    p.root().join("target").move_into_the_past();

    assert_that(p.cargo("build"),
                execs().with_status(0));
    assert_that(p.cargo("test").arg("-v"),
                execs().with_status(101));
}

#[test]
fn no_rebuild_transitive_target_deps() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            a = { path = "a" }
            [dev-dependencies]
            b = { path = "b" }
        "#)
        .file("src/lib.rs", "")
        .file("tests/foo.rs", "")
        .file("a/Cargo.toml", r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target.foo.dependencies]
            c = { path = "../c" }
        "#)
        .file("a/src/lib.rs", "")
        .file("b/Cargo.toml", r#"
            [package]
            name = "b"
            version = "0.0.1"
            authors = []

            [dependencies]
            c = { path = "../c" }
        "#)
        .file("b/src/lib.rs", "")
        .file("c/Cargo.toml", r#"
            [package]
            name = "c"
            version = "0.0.1"
            authors = []
        "#)
        .file("c/src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0));
    assert_that(p.cargo("test").arg("--no-run"),
                execs().with_status(0)
                       .with_stderr("\
[COMPILING] c v0.0.1 ([..])
[COMPILING] b v0.0.1 ([..])
[COMPILING] foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));
}

#[test]
fn rerun_if_changed_in_dep() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            a = { path = "a" }
        "#)
        .file("src/lib.rs", "")
        .file("a/Cargo.toml", r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []
            build = "build.rs"
        "#)
        .file("a/build.rs", r#"
            fn main() {
                println!("cargo:rerun-if-changed=build.rs");
            }
        "#)
        .file("a/src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0));
    assert_that(p.cargo("build"),
                execs().with_status(0).with_stdout(""));
}

#[test]
fn same_build_dir_cached_packages() {
    let p = project("foo")
        .file("a1/Cargo.toml", r#"
            [package]
            name = "a1"
            version = "0.0.1"
            authors = []
            [dependencies]
            b = { path = "../b" }
        "#)
        .file("a1/src/lib.rs", "")
        .file("a2/Cargo.toml", r#"
            [package]
            name = "a2"
            version = "0.0.1"
            authors = []
            [dependencies]
            b = { path = "../b" }
        "#)
        .file("a2/src/lib.rs", "")
        .file("b/Cargo.toml", r#"
            [package]
            name = "b"
            version = "0.0.1"
            authors = []
            [dependencies]
            c = { path = "../c" }
        "#)
        .file("b/src/lib.rs", "")
        .file("c/Cargo.toml", r#"
            [package]
            name = "c"
            version = "0.0.1"
            authors = []
            [dependencies]
            d = { path = "../d" }
        "#)
        .file("c/src/lib.rs", "")
        .file("d/Cargo.toml", r#"
            [package]
            name = "d"
            version = "0.0.1"
            authors = []
        "#)
        .file("d/src/lib.rs", "")
        .file(".cargo/config", r#"
            [build]
            target-dir = "./target"
        "#);
    p.build();

    assert_that(p.cargo("build").cwd(p.root().join("a1")),
                execs().with_status(0).with_stderr(&format!("\
[COMPILING] d v0.0.1 ({dir}/d)
[COMPILING] c v0.0.1 ({dir}/c)
[COMPILING] b v0.0.1 ({dir}/b)
[COMPILING] a1 v0.0.1 ({dir}/a1)
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", dir = p.url())));
    assert_that(p.cargo("build").cwd(p.root().join("a2")),
                execs().with_status(0).with_stderr(&format!("\
[COMPILING] a2 v0.0.1 ({dir}/a2)
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", dir = p.url())));
}

#[test]
fn no_rebuild_if_build_artifacts_move_backwards_in_time() {
    let p = project("backwards_in_time")
        .file("Cargo.toml", r#"
            [package]
            name = "backwards_in_time"
            version = "0.0.1"
            authors = []

            [dependencies]
            a = { path = "a" }
        "#)
        .file("src/lib.rs", "")
        .file("a/Cargo.toml", r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []
        "#)
        .file("a/src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0));

    p.root().move_into_the_past();
    p.root().join("target").move_into_the_past();

    assert_that(p.cargo("build").env("RUST_LOG", ""),
                execs().with_status(0).with_stdout("").with_stderr(""));
}

#[test]
fn rebuild_if_build_artifacts_move_forward_in_time() {
    let p = project("forwards_in_time")
        .file("Cargo.toml", r#"
            [package]
            name = "forwards_in_time"
            version = "0.0.1"
            authors = []

            [dependencies]
            a = { path = "a" }
        "#)
        .file("src/lib.rs", "")
        .file("a/Cargo.toml", r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []
        "#)
        .file("a/src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0));

    p.root().move_into_the_future();
    p.root().join("target").move_into_the_future();

    assert_that(p.cargo("build").env("RUST_LOG", ""),
                execs().with_status(0).with_stdout("").with_stderr("\
[COMPILING] a v0.0.1 ([..])
[COMPILING] forwards_in_time v0.0.1 ([..])
"));
}
<commit_msg>Fix some tests from the previous merge<commit_after>extern crate cargotest;
extern crate hamcrest;

use std::fs::{self, File};
use std::io::prelude::*;

use cargotest::sleep_ms;
use cargotest::support::{project, execs, path2url};
use cargotest::support::paths::CargoPathExt;
use hamcrest::{assert_that, existing_file};

#[test]
fn modifying_and_moving() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.1"
        "#)
        .file("src/main.rs", r#"
            mod a; fn main() {}
        "#)
        .file("src/a.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0).with_stderr(format!("\
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", dir = path2url(p.root()))));

    assert_that(p.cargo("build"),
                execs().with_status(0).with_stdout(""));
    p.root().move_into_the_past();
    p.root().join("target").move_into_the_past();

    File::create(&p.root().join("src/a.rs")).unwrap()
         .write_all(b"#[allow(unused)]fn main() {}").unwrap();
    assert_that(p.cargo("build"),
                execs().with_status(0).with_stderr(format!("\
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", dir = path2url(p.root()))));

    fs::rename(&p.root().join("src/a.rs"), &p.root().join("src/b.rs")).unwrap();
    assert_that(p.cargo("build"),
                execs().with_status(101));
}

#[test]
fn modify_only_some_files() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.1"
        "#)
        .file("src/lib.rs", "mod a;")
        .file("src/a.rs", "")
        .file("src/main.rs", r#"
            mod b;
            fn main() {}
        "#)
        .file("src/b.rs", "")
        .file("tests/test.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0).with_stderr(format!("\
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", dir = path2url(p.root()))));
    assert_that(p.cargo("test"),
                execs().with_status(0));
    sleep_ms(1000);

    assert_that(&p.bin("foo"), existing_file());

    let lib = p.root().join("src/lib.rs");
    let bin = p.root().join("src/b.rs");

    File::create(&lib).unwrap().write_all(b"invalid rust code").unwrap();
    File::create(&bin).unwrap().write_all(b"#[allow(unused)]fn foo() {}").unwrap();
    lib.move_into_the_past();

    // Make sure the binary is rebuilt, not the lib
    assert_that(p.cargo("build"),
                execs().with_status(0).with_stderr(format!("\
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", dir = path2url(p.root()))));
    assert_that(&p.bin("foo"), existing_file());
}

#[test]
fn rebuild_sub_package_then_while_package() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.1"

            [dependencies.a]
            path = "a"
            [dependencies.b]
            path = "b"
        "#)
        .file("src/lib.rs", "extern crate a; extern crate b;")
        .file("a/Cargo.toml", r#"
            [package]
            name = "a"
            authors = []
            version = "0.0.1"
            [dependencies.b]
            path = "../b"
        "#)
        .file("a/src/lib.rs", "extern crate b;")
        .file("b/Cargo.toml", r#"
            [package]
            name = "b"
            authors = []
            version = "0.0.1"
        "#)
        .file("b/src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0));

    File::create(&p.root().join("b/src/lib.rs")).unwrap().write_all(br#"
        pub fn b() {}
    "#).unwrap();

    assert_that(p.cargo("build").arg("-pb"),
                execs().with_status(0));

    File::create(&p.root().join("src/lib.rs")).unwrap().write_all(br#"
        extern crate a;
        extern crate b;
        pub fn toplevel() {}
    "#).unwrap();

    assert_that(p.cargo("build"),
                execs().with_status(0));
}

#[test]
fn changing_features_is_ok() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.1"

            [features]
            foo = []
        "#)
        .file("src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0)
                       .with_stderr("\
[..]Compiling foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));

    assert_that(p.cargo("build").arg("--features").arg("foo"),
                execs().with_status(0)
                       .with_stderr("\
[..]Compiling foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));

    assert_that(p.cargo("build"),
                execs().with_status(0)
                       .with_stderr("\
[..]Compiling foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));

    assert_that(p.cargo("build"),
                execs().with_status(0)
                       .with_stdout(""));
}

#[test]
fn rebuild_tests_if_lib_changes() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []
        "#)
        .file("src/lib.rs", "pub fn foo() {}")
        .file("tests/foo.rs", r#"
            extern crate foo;
            #[test]
            fn test() { foo::foo(); }
        "#);

    assert_that(p.cargo_process("build"),
                execs().with_status(0));
    assert_that(p.cargo("test"),
                execs().with_status(0));

    File::create(&p.root().join("src/lib.rs")).unwrap();
    p.root().move_into_the_past();
    p.root().join("target").move_into_the_past();

    assert_that(p.cargo("build"),
                execs().with_status(0));
    assert_that(p.cargo("test").arg("-v"),
                execs().with_status(101));
}

#[test]
fn no_rebuild_transitive_target_deps() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            a = { path = "a" }
            [dev-dependencies]
            b = { path = "b" }
        "#)
        .file("src/lib.rs", "")
        .file("tests/foo.rs", "")
        .file("a/Cargo.toml", r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target.foo.dependencies]
            c = { path = "../c" }
        "#)
        .file("a/src/lib.rs", "")
        .file("b/Cargo.toml", r#"
            [package]
            name = "b"
            version = "0.0.1"
            authors = []

            [dependencies]
            c = { path = "../c" }
        "#)
        .file("b/src/lib.rs", "")
        .file("c/Cargo.toml", r#"
            [package]
            name = "c"
            version = "0.0.1"
            authors = []
        "#)
        .file("c/src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0));
    assert_that(p.cargo("test").arg("--no-run"),
                execs().with_status(0)
                       .with_stderr("\
[COMPILING] c v0.0.1 ([..])
[COMPILING] b v0.0.1 ([..])
[COMPILING] foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));
}

#[test]
fn rerun_if_changed_in_dep() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            a = { path = "a" }
        "#)
        .file("src/lib.rs", "")
        .file("a/Cargo.toml", r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []
            build = "build.rs"
        "#)
        .file("a/build.rs", r#"
            fn main() {
                println!("cargo:rerun-if-changed=build.rs");
            }
        "#)
        .file("a/src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0));
    assert_that(p.cargo("build"),
                execs().with_status(0).with_stdout(""));
}

#[test]
fn same_build_dir_cached_packages() {
    let p = project("foo")
        .file("a1/Cargo.toml", r#"
            [package]
            name = "a1"
            version = "0.0.1"
            authors = []
            [dependencies]
            b = { path = "../b" }
        "#)
        .file("a1/src/lib.rs", "")
        .file("a2/Cargo.toml", r#"
            [package]
            name = "a2"
            version = "0.0.1"
            authors = []
            [dependencies]
            b = { path = "../b" }
        "#)
        .file("a2/src/lib.rs", "")
        .file("b/Cargo.toml", r#"
            [package]
            name = "b"
            version = "0.0.1"
            authors = []
            [dependencies]
            c = { path = "../c" }
        "#)
        .file("b/src/lib.rs", "")
        .file("c/Cargo.toml", r#"
            [package]
            name = "c"
            version = "0.0.1"
            authors = []
            [dependencies]
            d = { path = "../d" }
        "#)
        .file("c/src/lib.rs", "")
        .file("d/Cargo.toml", r#"
            [package]
            name = "d"
            version = "0.0.1"
            authors = []
        "#)
        .file("d/src/lib.rs", "")
        .file(".cargo/config", r#"
            [build]
            target-dir = "./target"
        "#);
    p.build();

    assert_that(p.cargo("build").cwd(p.root().join("a1")),
                execs().with_status(0).with_stderr(&format!("\
[COMPILING] d v0.0.1 ({dir}/d)
[COMPILING] c v0.0.1 ({dir}/c)
[COMPILING] b v0.0.1 ({dir}/b)
[COMPILING] a1 v0.0.1 ({dir}/a1)
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", dir = p.url())));
    assert_that(p.cargo("build").cwd(p.root().join("a2")),
                execs().with_status(0).with_stderr(&format!("\
[COMPILING] a2 v0.0.1 ({dir}/a2)
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", dir = p.url())));
}

#[test]
fn no_rebuild_if_build_artifacts_move_backwards_in_time() {
    let p = project("backwards_in_time")
        .file("Cargo.toml", r#"
            [package]
            name = "backwards_in_time"
            version = "0.0.1"
            authors = []

            [dependencies]
            a = { path = "a" }
        "#)
        .file("src/lib.rs", "")
        .file("a/Cargo.toml", r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []
        "#)
        .file("a/src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0));

    p.root().move_into_the_past();

    assert_that(p.cargo("build"),
                execs().with_status(0).with_stdout("").with_stderr("\
[FINISHED] [..]
"));
}

#[test]
fn rebuild_if_build_artifacts_move_forward_in_time() {
    let p = project("forwards_in_time")
        .file("Cargo.toml", r#"
            [package]
            name = "forwards_in_time"
            version = "0.0.1"
            authors = []

            [dependencies]
            a = { path = "a" }
        "#)
        .file("src/lib.rs", "")
        .file("a/Cargo.toml", r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []
        "#)
        .file("a/src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(0));

    p.root().move_into_the_future();

    assert_that(p.cargo("build").env("RUST_LOG", ""),
                execs().with_status(0).with_stdout("").with_stderr("\
[COMPILING] a v0.0.1 ([..])
[COMPILING] forwards_in_time v0.0.1 ([..])
[FINISHED] [..]
"));
}
<|endoftext|>


<commit_before>/**
 * Miscellaneous helpers for common patterns.
 */

/// The identity function.
pure fn id<T>(+x: T) -> T { x }

/**
 * Swap the values at two mutable locations of the same type, without
 * deinitialising or copying either one.
 */
#[inline(always)]
fn swap<T>(x: &mut T, y: &mut T) {
    *x <-> *y;
}

/**
 * Replace the value at a mutable location with a new one, returning the old
 * value, without deinitialising or copying either one.
 */
#[inline(always)]
fn replace<T>(dest: &mut T, +src: T) -> T {
    let mut tmp = src;
    swap(dest, &mut tmp);
    tmp
}

/// A non-copyable dummy type.
class noncopyable {
    i: ();
    new() { self.i = (); }
    drop { }
}

mod tests {
    #[test]
    fn identity_crisis() {
        // Writing a test for the identity function. How did it come to this?
        let x = ~[{mut a: 5, b: false}];
        assert x == id(copy x);
    }
    #[test]
    fn test_swap() {
        let mut x = 31337;
        let mut y = 42;
        swap(&mut x, &mut y);
        assert x == 42;
        assert y == 31337;
    }
    #[test]
    fn test_replace() {
        let mut x = some(noncopyable());
        let y = replace(&mut x, none);
        assert x.is_none();
        assert y.is_some();
    }
}
<commit_msg>Add util::ignore<commit_after>/**
 * Miscellaneous helpers for common patterns.
 */

/// The identity function.
pure fn id<T>(+x: T) -> T { x }

/// Ignores a value.
pure fn ignore<T>(+_x: T) { }

/**
 * Swap the values at two mutable locations of the same type, without
 * deinitialising or copying either one.
 */
#[inline(always)]
fn swap<T>(x: &mut T, y: &mut T) {
    *x <-> *y;
}

/**
 * Replace the value at a mutable location with a new one, returning the old
 * value, without deinitialising or copying either one.
 */
#[inline(always)]
fn replace<T>(dest: &mut T, +src: T) -> T {
    let mut tmp = src;
    swap(dest, &mut tmp);
    tmp
}

/// A non-copyable dummy type.
class noncopyable {
    i: ();
    new() { self.i = (); }
    drop { }
}

mod tests {
    #[test]
    fn identity_crisis() {
        // Writing a test for the identity function. How did it come to this?
        let x = ~[{mut a: 5, b: false}];
        assert x == id(copy x);
    }
    #[test]
    fn test_swap() {
        let mut x = 31337;
        let mut y = 42;
        swap(&mut x, &mut y);
        assert x == 42;
        assert y == 31337;
    }
    #[test]
    fn test_replace() {
        let mut x = some(noncopyable());
        let y = replace(&mut x, none);
        assert x.is_none();
        assert y.is_some();
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Type representing virtual addresses.

use core::fmt;
use core::ops;

/// A virtual address is a machine-sized unsigned integer
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct VAddr(usize);

impl VAddr {
    #[inline] pub const fn from_usize(u: usize) -> Self {
        VAddr(u)
    }
    #[inline] pub const fn as_usize(&self) -> usize {
        self.0
    }

    /// Calculate the index in the PML4 table corresponding to this address.
    #[inline] pub fn pml4_index(&self) -> usize {
        (*self >> 39) & 0b111111111
    }

    /// Calculate the index in the PDPT table corresponding to this address.
    #[inline] pub fn pdpt_index(&self) -> usize {
        (*self >> 30) & 0b111111111
    }

    /// Calculate the index in the PD table corresponding to this address.
    #[inline] pub fn pd_index(&self) -> usize {
        (*self >> 21) & 0b111111111
    }

    /// Calculate the index in the PT table corresponding to this address.
    #[inline] pub fn pt_index(&self) -> usize {
        (*self >> 12) & 0b111111111
    }
}

impl fmt::Binary for VAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Display for VAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::LowerHex for VAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Octal for VAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::UpperHex for VAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl ops::Add<VAddr> for VAddr {
    type Output = VAddr;

    fn add(self, _rhs: VAddr) -> VAddr {
        VAddr(self.0 + _rhs.0)
    }
}

impl ops::Sub<VAddr> for VAddr {
    type Output = VAddr;

    fn sub(self, _rhs: VAddr) -> VAddr {
        VAddr(self.0 - _rhs.0)
    }
}

impl ops::Div<VAddr> for VAddr {
    type Output = VAddr;

    fn div(self, _rhs: VAddr) -> VAddr {
        VAddr(self.0 / _rhs.0)
    }
}

impl ops::Mul<VAddr> for VAddr {
    type Output = VAddr;

    fn mul(self, _rhs: VAddr) -> VAddr {
        VAddr(self.0 * _rhs.0)
    }
}

impl ops::Add<usize> for VAddr {
    type Output = VAddr;

    fn add(self, _rhs: usize) -> VAddr {
        VAddr(self.0 + _rhs)
    }
}

impl ops::Sub<usize> for VAddr {
    type Output = VAddr;

    fn sub(self, _rhs: usize) -> VAddr {
        VAddr(self.0 - _rhs)
    }
}

impl ops::Div<usize> for VAddr {
    type Output = VAddr;

    fn div(self, _rhs: usize) -> VAddr {
        VAddr(self.0 / _rhs)
    }
}

impl ops::Mul<usize> for VAddr {
    type Output = VAddr;

    fn mul(self, _rhs: usize) -> VAddr {
        VAddr(self.0 * _rhs)
    }
}

impl ops::Shl<usize> for VAddr {
    type Output = VAddr;

    fn shl(self, _rhs: usize) -> VAddr {
        VAddr(self.0 << _rhs)
    }
}

impl ops::Shr<usize> for VAddr {
    type Output = VAddr;

    fn shr(self, _rhs: usize) -> VAddr {
        VAddr(self.0 >> _rhs)
    }
}

impl ops::BitAnd<usize> for VAddr {
    type Output = usize;

    fn bitand(self, _rhs: usize) -> usize {
        self.0 & _rhs
    }
}
<commit_msg>[kernel] All numeric ops can now be used on VAddrs Macros make everything easier!<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Type representing virtual addresses.

use core::fmt;
use core::ops;

/// A virtual address is a machine-sized unsigned integer
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct VAddr(usize);

impl VAddr {
    #[inline] pub const fn from_usize(u: usize) -> Self {
        VAddr(u)
    }
    #[inline] pub const fn as_usize(&self) -> usize {
        self.0
    }

    /// Calculate the index in the PML4 table corresponding to this address.
    #[inline] pub fn pml4_index(&self) -> usize {
        (self >> 39) & 0b111111111
    }

    /// Calculate the index in the PDPT table corresponding to this address.
    #[inline] pub fn pdpt_index(&self) -> usize {
        (self >> 30) & 0b111111111
    }

    /// Calculate the index in the PD table corresponding to this address.
    #[inline] pub fn pd_index(&self) -> usize {
        (self >> 21) & 0b111111111
    }

    /// Calculate the index in the PT table corresponding to this address.
    #[inline] pub fn pt_index(&self) -> usize {
        (self >> 12) & 0b111111111
    }
}

impl fmt::Binary for VAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Display for VAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::LowerHex for VAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Octal for VAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::UpperHex for VAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}
macro_rules! forward_ref_binop {
    (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
        impl<'a> ops::$imp<$u> for &'a $t {
            type Output = <$t as ops::$imp<$u>>::Output;
            #[inline]
            fn $method(self, other: $u) -> <$t as ops::$imp<$u>>::Output {
                ops::$imp::$method(*self, other)
            }
        }

        impl<'a> ops::$imp<&'a $u> for $t {
            type Output = <$t as ops::$imp<$u>>::Output;
            #[inline]
            fn $method(self, other: &'a $u) -> <$t as ops::$imp<$u>>::Output {
                ops::$imp::$method(self, *other)
            }
        }

        impl<'a, 'b> ops::$imp<&'a $u> for &'b $t {
            type Output = <$t as ops::$imp<$u>>::Output;

            #[inline]
            fn $method(self, other: &'a $u) -> <$t as ops::$imp<$u>>::Output {
                ops::$imp::$method(*self, *other)
            }
        }
    }
}
macro_rules! e { ($e:expr) => { $e } }
macro_rules! impl_ops {
    ($(impl $name:ident, $fun:ident, $op:tt for VAddr)*) => {$(
        impl ops::$name<VAddr> for VAddr {
            type Output = VAddr;

            #[inline] fn $fun(self, _rhs: VAddr) -> VAddr {
                VAddr(e!(self.0 $op _rhs.0))
            }
        }
        impl ops::$name<usize> for VAddr {
            type Output = VAddr;

            #[inline] fn $fun(self, _rhs: usize) -> VAddr {
                VAddr(e!(self.0 $op _rhs))
            }
        }

        forward_ref_binop! {
            impl $name, $fun for VAddr, VAddr
        }
        forward_ref_binop! {
            impl $name, $fun for VAddr, usize
        }
    )*}
}
macro_rules! impl_fmt {
    ($($name:ident),*) => {$(
        impl fmt::$name for VAddr {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                self.0.fmt(f)
            }
        }
    )*}
}

impl_ops! {
    impl Add, add, + for VAddr
    impl Sub, sub, - for VAddr
    impl Div, div, / for VAddr
    impl Mul, mul, * for VAddr
    impl Shl, shl, >> for VAddr
    impl Shr, shr, << for VAddr
}

impl ops::BitAnd<usize> for VAddr {
    type Output = usize;

    fn bitand(self, _rhs: usize) -> usize {
        self.0 & _rhs
    }
}
<|endoftext|>


<commit_before>use lfsr::fibonacci::FibonacciLFSR;
use lfsr::galois::GaloisLFSR;

use support::eq_mod_rotation;

#[test]
fn iter_works_for_fibonacci() {
    iter_works_for!(FibonacciLFSR);
}

#[test]
fn iter_works_for_galois() {
    iter_works_for!(GaloisLFSR);
}

#[test]
fn same_connection_polynomial_produce_output_equal_mod_rotation() {
    let taps = vec![2, 3];

    let mut galois = GaloisLFSR::from_iter(taps.iter());
    let galois_output: Vec<bool> = galois.iter().take(7).collect();

    let mut fibonacci = FibonacciLFSR::from_iter(taps.iter());
    let fibonacci_output: Vec<bool> = fibonacci.iter().take(7).collect();

    assert!(eq_mod_rotation(&fibonacci_output, &galois_output));
}

#[test]
fn primitive_connection_polynomial_yields_a_maximum_sequence_for_fibonacci() {
    primitive_connection_polynomial_yields_a_maximum_sequence!(FibonacciLFSR);
}

#[test]
fn primitive_connection_polynomial_yields_a_maximum_sequence_for_galois() {
    primitive_connection_polynomial_yields_a_maximum_sequence!(GaloisLFSR);
}

#[test]
fn implements_iter() {
    let taps = vec![2, 3];
    let mut lfsr = GaloisLFSR::from_iter(taps.iter());

    let output: Vec<bool> = lfsr.iter().take(8).collect();

    let expected = vec![true, false, false, true, false, true, true, true];

    assert!(eq_mod_rotation(&output, &expected))
}

#[test]
fn implements_into_iterator() {
    let taps = vec![2, 3];
    let lfsr = GaloisLFSR::from_iter(taps.iter());

    let mut counter = 0;
    for _b in lfsr {
        if counter == 3 {
            break;
        }
        counter += 1;
    }
}

#[test]
fn implements_into_iterator_for_mut_refs() {
    use lfsr::LFSR;

    let taps = vec![2, 3];
    let mut lfsr = GaloisLFSR::from_iter(taps.iter());

    let mut counter = 0;
    for _b in &mut lfsr {
        if counter == 3 {
            break;
        }
        counter += 1;
    }

    lfsr.step();
}
<commit_msg>Specialize test names<commit_after>use lfsr::fibonacci::FibonacciLFSR;
use lfsr::galois::GaloisLFSR;

use support::eq_mod_rotation;

#[test]
fn iter_works_for_fibonacci() {
    iter_works_for!(FibonacciLFSR);
}

#[test]
fn iter_works_for_galois() {
    iter_works_for!(GaloisLFSR);
}

#[test]
fn same_connection_polynomial_produce_output_equal_mod_rotation() {
    let taps = vec![2, 3];

    let mut galois = GaloisLFSR::from_iter(taps.iter());
    let galois_output: Vec<bool> = galois.iter().take(7).collect();

    let mut fibonacci = FibonacciLFSR::from_iter(taps.iter());
    let fibonacci_output: Vec<bool> = fibonacci.iter().take(7).collect();

    assert!(eq_mod_rotation(&fibonacci_output, &galois_output));
}

#[test]
fn primitive_connection_polynomial_yields_a_maximum_sequence_for_fibonacci() {
    primitive_connection_polynomial_yields_a_maximum_sequence!(FibonacciLFSR);
}

#[test]
fn primitive_connection_polynomial_yields_a_maximum_sequence_for_galois() {
    primitive_connection_polynomial_yields_a_maximum_sequence!(GaloisLFSR);
}

#[test]
fn implements_iter_for_galois() {
    let taps = vec![2, 3];
    let mut lfsr = GaloisLFSR::from_iter(taps.iter());

    let output: Vec<bool> = lfsr.iter().take(8).collect();

    let expected = vec![true, false, false, true, false, true, true, true];

    assert!(eq_mod_rotation(&output, &expected))
}

#[test]
fn implements_into_iterator_for_galois() {
    let taps = vec![2, 3];
    let lfsr = GaloisLFSR::from_iter(taps.iter());

    let mut counter = 0;
    for _b in lfsr {
        if counter == 3 {
            break;
        }
        counter += 1;
    }
}

#[test]
fn implements_into_iterator_for_mut_refs_for_galois() {
    use lfsr::LFSR;

    let taps = vec![2, 3];
    let mut lfsr = GaloisLFSR::from_iter(taps.iter());

    let mut counter = 0;
    for _b in &mut lfsr {
        if counter == 3 {
            break;
        }
        counter += 1;
    }

    lfsr.step();
}
<|endoftext|>


<commit_before>use memory::VAddr;
use super::{Page, VirtualPage};

/// Invalidate the TLB completely by reloading the CR3 register.
///
/// # Unsafe Because
/// + Causes a general protection fault if not executed in kernel mode.
pub unsafe fn flush_all() {
    use cpu::control_regs::cr3;
    cr3::write(cr3::read());
}

/// Something which may be flushed from the TLB
pub trait Flush {
    /// Invalidate this object in the TLB using the `invlpg` instruction.
    ///
    /// # Unsafe Because
    /// + Causes a general protection fault if not executed in kernel mode.
    unsafe fn invlpg(&self);

    /// Invalidate this object in the TLB instruction if we are in kernel mode.
    ///
    /// # Returns
    /// + True if the object was flushed
    /// + False if it was not flushed.
    #[inline]
    fn flush(&self) -> bool {
        use cpu::PrivilegeLevel;

        if PrivilegeLevel::current_iopl() != PrivilegeLevel::KernelMode {
            false // can't flush, we are not in kernel mode
        } else {
            // this is safe since we know we are in kernel mode
            unsafe { self.invlpg() };
            true
        }
    }
}

impl Flush for VAddr {
    #[inline]
    unsafe fn invlpg(&self) {
         asm!( "invlpg [$0]"
             :
             : "r" (*self)
             : "memory"
             : "intel", "volatile" );
    }
}

impl Flush for VirtualPage {
    #[inline]
    unsafe fn invlpg(&self) {
        self.base().invlpg()
    }
}
<commit_msg>[paging] fix use of struct as immediate in tlb::invlpg<commit_after>use memory::VAddr;
use super::{Page, VirtualPage};

/// Invalidate the TLB completely by reloading the CR3 register.
///
/// # Unsafe Because
/// + Causes a general protection fault if not executed in kernel mode.
pub unsafe fn flush_all() {
    use cpu::control_regs::cr3;
    cr3::write(cr3::read());
}

/// Something which may be flushed from the TLB
pub trait Flush {
    /// Invalidate this object in the TLB using the `invlpg` instruction.
    ///
    /// # Unsafe Because
    /// + Causes a general protection fault if not executed in kernel mode.
    unsafe fn invlpg(&self);

    /// Invalidate this object in the TLB instruction if we are in kernel mode.
    ///
    /// # Returns
    /// + True if the object was flushed
    /// + False if it was not flushed.
    #[inline]
    fn flush(&self) -> bool {
        use cpu::PrivilegeLevel;

        if PrivilegeLevel::current_iopl() != PrivilegeLevel::KernelMode {
            false // can't flush, we are not in kernel mode
        } else {
            // this is safe since we know we are in kernel mode
            unsafe { self.invlpg() };
            true
        }
    }
}

impl Flush for VAddr {
    #[inline]
    unsafe fn invlpg(&self) {
         asm!( "invlpg [$0]"
             :
             : "r" (**self)
             : "memory"
             : "intel", "volatile" );
    }
}

impl Flush for VirtualPage {
    #[inline]
    unsafe fn invlpg(&self) {
        self.base().invlpg()
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate petgraph;

use rand::{Rng, thread_rng, ChaChaRng};
use std::collections::HashSet;
use petgraph::unionfind::UnionFind;

#[test]
fn uf_test() {
    let n = 8;
    let mut u = UnionFind::new(n);
    for i in 0..n {
        assert_eq!(u.find(i), i);
        assert_eq!(u.find_mut(i), i);
        assert!(!u.union(i, i));
    }

    u.union(0, 1);
    assert_eq!(u.find(0), u.find(1));
    u.union(1, 3);
    u.union(1, 4);
    u.union(4, 7);
    assert_eq!(u.find(0), u.find(3));
    assert_eq!(u.find(1), u.find(3));
    assert!(u.find(0) != u.find(2));
    assert_eq!(u.find(7), u.find(0));
    u.union(5, 6);
    assert_eq!(u.find(6), u.find(5));
    assert!(u.find(6) != u.find(7));

    // check that there are now 3 disjoint sets
    let set = (0..n).map(|i| u.find(i)).collect::<HashSet<_>>();
    assert_eq!(set.len(), 3);
}

#[test]
fn uf_rand() {
    let n = 1 << 14;
    let mut rng: ChaChaRng = thread_rng().gen();
    let mut u = UnionFind::new(n);
    for i in 0..(n * 8) {
        let a = rng.gen_range(0, n);
        let b = rng.gen_range(0, n);
        let ar = u.find(a);
        let br = u.find(b);
        assert_eq!(ar != br, u.union(a, b));
        if (i + 1) % n == 0 {
            let set = (0..n).map(|i| u.find(i)).collect::<HashSet<_>>();
            println!("Disjoint parts={:?}", set.len());
            //println!("Disjoint parts={:?} maxrank={:?}", set.len(), u.rank.iter().max_by(|t| *t));
        }
    }
}

#[test]
fn uf_u8() {
    let n = 256;
    let mut rng: ChaChaRng = thread_rng().gen();
    let mut u = UnionFind::<u8>::new(n);
    for _ in 0..(n * 8) {
        let a = rng.gen();
        let b = rng.gen();
        let ar = u.find(a);
        let br = u.find(b);
        assert_eq!(ar != br, u.union(a, b));
    }
}

#[test]
fn labeling()
{
    let mut u = UnionFind::<u32>::new(48);
    for i in (0..24) {
        u.union(i + 1, i);
    }
    for i in (25..47) {
        u.union(i, i + 1);
    }
    u.union(23, 25);
    u.union(24, 23);
    let v = u.into_labeling();
    assert!(v.iter().all(|x| *x == v[0]));
}
<commit_msg>tests: Shorten unionfind test<commit_after>extern crate rand;
extern crate petgraph;

use rand::{Rng, thread_rng, ChaChaRng};
use std::collections::HashSet;
use petgraph::unionfind::UnionFind;

#[test]
fn uf_test() {
    let n = 8;
    let mut u = UnionFind::new(n);
    for i in 0..n {
        assert_eq!(u.find(i), i);
        assert_eq!(u.find_mut(i), i);
        assert!(!u.union(i, i));
    }

    u.union(0, 1);
    assert_eq!(u.find(0), u.find(1));
    u.union(1, 3);
    u.union(1, 4);
    u.union(4, 7);
    assert_eq!(u.find(0), u.find(3));
    assert_eq!(u.find(1), u.find(3));
    assert!(u.find(0) != u.find(2));
    assert_eq!(u.find(7), u.find(0));
    u.union(5, 6);
    assert_eq!(u.find(6), u.find(5));
    assert!(u.find(6) != u.find(7));

    // check that there are now 3 disjoint sets
    let set = (0..n).map(|i| u.find(i)).collect::<HashSet<_>>();
    assert_eq!(set.len(), 3);
}

#[test]
fn uf_rand() {
    let n = 1 << 14;
    let mut rng: ChaChaRng = thread_rng().gen();
    let mut u = UnionFind::new(n);
    for _ in 0..100 {
        let a = rng.gen_range(0, n);
        let b = rng.gen_range(0, n);
        let ar = u.find(a);
        let br = u.find(b);
        assert_eq!(ar != br, u.union(a, b));
    }
}

#[test]
fn uf_u8() {
    let n = 256;
    let mut rng: ChaChaRng = thread_rng().gen();
    let mut u = UnionFind::<u8>::new(n);
    for _ in 0..(n * 8) {
        let a = rng.gen();
        let b = rng.gen();
        let ar = u.find(a);
        let br = u.find(b);
        assert_eq!(ar != br, u.union(a, b));
    }
}

#[test]
fn labeling()
{
    let mut u = UnionFind::<u32>::new(48);
    for i in (0..24) {
        u.union(i + 1, i);
    }
    for i in (25..47) {
        u.union(i, i + 1);
    }
    u.union(23, 25);
    u.union(24, 23);
    let v = u.into_labeling();
    assert!(v.iter().all(|x| *x == v[0]));
}
<|endoftext|>


<commit_before>// This is a part of rust-chrono.
// Copyright (c) 2015, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

/*!
 * The local (system) time zone.
 */

use stdtime;

use {Datelike, Timelike};
use duration::Duration;
use naive::date::NaiveDate;
use naive::time::NaiveTime;
use naive::datetime::NaiveDateTime;
use date::Date;
use datetime::DateTime;
use super::{TimeZone, LocalResult};
use super::fixed::FixedOffset;

/// Converts a `time::Tm` struct into the timezone-aware `DateTime`.
/// This assumes that `time` is working correctly, i.e. any error is fatal.
fn tm_to_datetime(mut tm: stdtime::Tm) -> DateTime<Local> {
    if tm.tm_sec >= 60 {
        tm.tm_sec = 59;
        tm.tm_nsec += (tm.tm_sec - 59) * 1_000_000_000;
    }

    // from_yo is more efficient than from_ymd (since it's the internal representation).
    let date = NaiveDate::from_yo(tm.tm_year + 1900, tm.tm_yday as u32 + 1);
    let time = NaiveTime::from_hms_nano(tm.tm_hour as u32, tm.tm_min as u32,
                                        tm.tm_sec as u32, tm.tm_nsec as u32);
    let offset = FixedOffset::east(tm.tm_utcoff);
    DateTime::from_utc(date.and_time(time) + Duration::seconds(-tm.tm_utcoff as i64), offset)
}

/// Converts a local `NaiveDateTime` to the `time::Timespec`.
fn datetime_to_timespec(d: &NaiveDateTime, local: bool) -> stdtime::Timespec {
    // well, this exploits an undocumented `Tm::to_timespec` behavior
    // to get the exact function we want (either `timegm` or `mktime`).
    // the number 1 is arbitrary but should be non-zero to trigger `mktime`.
    let tm_utcoff = if local {1} else {0};

    let tm = stdtime::Tm {
        tm_sec: d.second() as i32,
        tm_min: d.minute() as i32,
        tm_hour: d.hour() as i32,
        tm_mday: d.day() as i32,
        tm_mon: d.month0() as i32, // yes, C is that strange...
        tm_year: d.year() - 1900, // this doesn't underflow, we know that d is `NaiveDateTime`.
        tm_wday: 0, // to_local ignores this
        tm_yday: 0, // and this
        tm_isdst: -1,
        tm_utcoff: tm_utcoff,
        tm_nsec: d.nanosecond() as i32,
    };
    tm.to_timespec()
}

/// The local timescale. This is implemented via the standard `time` crate.
#[derive(Copy, Clone)]
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
pub struct Local;

impl Local {
    /// Returns a `Date` which corresponds to the current date.
    pub fn today() -> Date<Local> {
        Local::now().date()
    }

    /// Returns a `DateTime` which corresponds to the current date.
    pub fn now() -> DateTime<Local> {
        tm_to_datetime(stdtime::now())
    }
}

impl TimeZone for Local {
    type Offset = FixedOffset;

    fn from_offset(_offset: &FixedOffset) -> Local { Local }

    // they are easier to define in terms of the finished date and time unlike other offsets
    fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<FixedOffset> {
        self.from_local_date(local).map(|date| *date.offset())
    }
    fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<FixedOffset> {
        self.from_local_datetime(local).map(|datetime| *datetime.offset())
    }

    fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset {
        *self.from_utc_date(utc).offset()
    }
    fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> FixedOffset {
        *self.from_utc_datetime(utc).offset()
    }

    // override them for avoiding redundant works
    fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Local>> {
        // this sounds very strange, but required for keeping `TimeZone::ymd` sane.
        // in the other words, we use the offset at the local midnight
        // but keep the actual date unaltered (much like `FixedOffset`).
        let midnight = self.from_local_datetime(&local.and_hms(0, 0, 0));
        midnight.map(|datetime| Date::from_utc(*local, datetime.offset().clone()))
    }
    fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Local>> {
        let timespec = datetime_to_timespec(local, true);
        LocalResult::Single(tm_to_datetime(stdtime::at(timespec)))
    }

    fn from_utc_date(&self, utc: &NaiveDate) -> Date<Local> {
        let midnight = self.from_utc_datetime(&utc.and_hms(0, 0, 0));
        Date::from_utc(*utc, midnight.offset().clone())
    }
    fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Local> {
        let timespec = datetime_to_timespec(utc, false);
        tm_to_datetime(stdtime::at(timespec))
    }
}

<commit_msg>Fix spilling of exceeding `tm_sec` into `tm_nsec` in `tm_to_datetime()`.<commit_after>// This is a part of rust-chrono.
// Copyright (c) 2015, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

/*!
 * The local (system) time zone.
 */

use stdtime;

use {Datelike, Timelike};
use duration::Duration;
use naive::date::NaiveDate;
use naive::time::NaiveTime;
use naive::datetime::NaiveDateTime;
use date::Date;
use datetime::DateTime;
use super::{TimeZone, LocalResult};
use super::fixed::FixedOffset;

/// Converts a `time::Tm` struct into the timezone-aware `DateTime`.
/// This assumes that `time` is working correctly, i.e. any error is fatal.
fn tm_to_datetime(mut tm: stdtime::Tm) -> DateTime<Local> {
    if tm.tm_sec >= 60 {
        tm.tm_nsec += (tm.tm_sec - 59) * 1_000_000_000;
        tm.tm_sec = 59;
    }

    // from_yo is more efficient than from_ymd (since it's the internal representation).
    let date = NaiveDate::from_yo(tm.tm_year + 1900, tm.tm_yday as u32 + 1);
    let time = NaiveTime::from_hms_nano(tm.tm_hour as u32, tm.tm_min as u32,
                                        tm.tm_sec as u32, tm.tm_nsec as u32);
    let offset = FixedOffset::east(tm.tm_utcoff);
    DateTime::from_utc(date.and_time(time) + Duration::seconds(-tm.tm_utcoff as i64), offset)
}

/// Converts a local `NaiveDateTime` to the `time::Timespec`.
fn datetime_to_timespec(d: &NaiveDateTime, local: bool) -> stdtime::Timespec {
    // well, this exploits an undocumented `Tm::to_timespec` behavior
    // to get the exact function we want (either `timegm` or `mktime`).
    // the number 1 is arbitrary but should be non-zero to trigger `mktime`.
    let tm_utcoff = if local {1} else {0};

    let tm = stdtime::Tm {
        tm_sec: d.second() as i32,
        tm_min: d.minute() as i32,
        tm_hour: d.hour() as i32,
        tm_mday: d.day() as i32,
        tm_mon: d.month0() as i32, // yes, C is that strange...
        tm_year: d.year() - 1900, // this doesn't underflow, we know that d is `NaiveDateTime`.
        tm_wday: 0, // to_local ignores this
        tm_yday: 0, // and this
        tm_isdst: -1,
        tm_utcoff: tm_utcoff,
        tm_nsec: d.nanosecond() as i32,
    };
    tm.to_timespec()
}

/// The local timescale. This is implemented via the standard `time` crate.
#[derive(Copy, Clone)]
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
pub struct Local;

impl Local {
    /// Returns a `Date` which corresponds to the current date.
    pub fn today() -> Date<Local> {
        Local::now().date()
    }

    /// Returns a `DateTime` which corresponds to the current date.
    pub fn now() -> DateTime<Local> {
        tm_to_datetime(stdtime::now())
    }
}

impl TimeZone for Local {
    type Offset = FixedOffset;

    fn from_offset(_offset: &FixedOffset) -> Local { Local }

    // they are easier to define in terms of the finished date and time unlike other offsets
    fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<FixedOffset> {
        self.from_local_date(local).map(|date| *date.offset())
    }
    fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<FixedOffset> {
        self.from_local_datetime(local).map(|datetime| *datetime.offset())
    }

    fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset {
        *self.from_utc_date(utc).offset()
    }
    fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> FixedOffset {
        *self.from_utc_datetime(utc).offset()
    }

    // override them for avoiding redundant works
    fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Local>> {
        // this sounds very strange, but required for keeping `TimeZone::ymd` sane.
        // in the other words, we use the offset at the local midnight
        // but keep the actual date unaltered (much like `FixedOffset`).
        let midnight = self.from_local_datetime(&local.and_hms(0, 0, 0));
        midnight.map(|datetime| Date::from_utc(*local, datetime.offset().clone()))
    }
    fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Local>> {
        let timespec = datetime_to_timespec(local, true);
        LocalResult::Single(tm_to_datetime(stdtime::at(timespec)))
    }

    fn from_utc_date(&self, utc: &NaiveDate) -> Date<Local> {
        let midnight = self.from_utc_datetime(&utc.and_hms(0, 0, 0));
        Date::from_utc(*utc, midnight.offset().clone())
    }
    fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Local> {
        let timespec = datetime_to_timespec(utc, false);
        tm_to_datetime(stdtime::at(timespec))
    }
}

<|endoftext|>