<commit_before>//! Statuses interface
use serde::{Deserialize, Serialize};

use crate::users::User;
use crate::{Future, Github};

/// interface for statuses associated with a repository
pub struct Statuses {
    github: Github,
    owner: String,
    repo: String,
}

impl Statuses {
    #[doc(hidden)]
    pub fn new<O, R>(github: Github, owner: O, repo: R) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        Statuses {
            github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/statuses{}", self.owner, self.repo, more)
    }

    /// creates a new status for a target sha
    pub fn create(&self, sha: &str, status: &StatusOptions) -> Future<Status> {
        self.github
            .post(&self.path(&format!("/{}", sha)), json!(status))
    }

    /// lists all statuses associated with a given git sha
    pub fn list(&self, sha: &str) -> Future<Vec<Status>> {
        self.github.get(&format!(
            "/repos/{}/{}/commits/{}/statuses",
            self.owner, self.repo, sha
        ))
    }

    /// list the combined statuses for a given git sha
    /// fixme: give this a type
    pub fn combined(&self, sha: &str) -> Future<String> {
        self.github.get(&format!(
            "/repos/{}/{}/commits/{}/status",
            self.owner, self.repo, sha
        ))
    }
}

// representations (todo: replace with derive_builder)

#[derive(Debug, Deserialize)]
pub struct Status {
    pub created_at: String,
    pub updated_at: String,
    pub state: State,
    pub target_url: String,
    pub description: String,
    pub id: u64,
    pub url: String,
    pub context: String,
    pub creator: User,
}

#[derive(Debug, Default, Serialize)]
pub struct StatusOptions {
    state: State,
    #[serde(skip_serializing_if = "Option::is_none")]
    target_url: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    context: Option<String>,
}

pub struct StatusOptionsBuilder(StatusOptions);

impl StatusOptionsBuilder {
    #[doc(hidden)]
    pub(crate) fn new(state: State) -> Self {
        StatusOptionsBuilder(StatusOptions {
            state,
            ..Default::default()
        })
    }

    pub fn target_url<T>(&mut self, url: T) -> &mut Self
    where
        T: Into<String>,
    {
        self.0.target_url = Some(url.into());
        self
    }

    pub fn description<D>(&mut self, desc: D) -> &mut Self
    where
        D: Into<String>,
    {
        self.0.description = Some(desc.into());
        self
    }

    pub fn context<C>(&mut self, ctx: C) -> &mut Self
    where
        C: Into<String>,
    {
        self.0.context = Some(ctx.into());
        self
    }

    pub fn build(&self) -> StatusOptions {
        StatusOptions::new(
            self.0.state.clone(),
            self.0.target_url.clone(),
            self.0.description.clone(),
            self.0.context.clone(),
        )
    }
}

impl StatusOptions {
    #[doc(hidden)]
    pub fn new<T, D, C>(
        state: State,
        target_url: Option<T>,
        descr: Option<D>,
        context: Option<C>,
    ) -> Self
    where
        T: Into<String>,
        D: Into<String>,
        C: Into<String>,
    {
        StatusOptions {
            state,
            target_url: target_url.map(|t| t.into()),
            description: descr.map(|d| d.into()),
            context: context.map(|c| c.into()),
        }
    }

    pub fn builder(state: State) -> StatusOptionsBuilder {
        StatusOptionsBuilder::new(state)
    }
}

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum State {
    /// pending
    #[serde(rename = "pending")]
    Pending,
    /// success
    #[serde(rename = "success")]
    Success,
    /// error
    #[serde(rename = "error")]
    Error,
    /// failure
    #[serde(rename = "failure")]
    Failure,
}

impl Default for State {
    fn default() -> State {
        State::Pending
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde::ser::Serialize;
    use serde_json;

    fn test_encoding<E: Serialize>(tests: Vec<(E, &str)>) {
        for test in tests {
            match test {
                (k, v) => assert_eq!(serde_json::to_string(&k).unwrap(), v),
            }
        }
    }

    #[test]
    fn deserialize_status_state() {
        for (json, value) in vec![
            ("\"pending\"", State::Pending),
            ("\"success\"", State::Success),
            ("\"error\"", State::Error),
            ("\"failure\"", State::Failure),
        ] {
            assert_eq!(serde_json::from_str::<State>(json).unwrap(), value)
        }
    }

    #[test]
    fn serialize_status_state() {
        for (json, value) in vec![
            ("\"pending\"", State::Pending),
            ("\"success\"", State::Success),
            ("\"error\"", State::Error),
            ("\"failure\"", State::Failure),
        ] {
            assert_eq!(serde_json::to_string(&value).unwrap(), json)
        }
    }

    #[test]
    fn status_reqs() {
        let tests = vec![
            (
                StatusOptions::builder(State::Pending).build(),
                r#"{"state":"pending"}"#,
            ),
            (
                StatusOptions::builder(State::Success)
                    .target_url("http://acme.com")
                    .build(),
                r#"{"state":"success","target_url":"http://acme.com"}"#,
            ),
            (
                StatusOptions::builder(State::Error)
                    .description("desc")
                    .build(),
                r#"{"state":"error","description":"desc"}"#,
            ),
            (
                StatusOptions::builder(State::Failure)
                    .target_url("http://acme.com")
                    .description("desc")
                    .build(),
                r#"{"state":"failure","target_url":"http://acme.com","description":"desc"}"#,
            ),
        ];
        test_encoding(tests)
    }

}
<commit_msg>Statuses.{created,updated}_at: optional<commit_after>//! Statuses interface
use serde::{Deserialize, Serialize};

use crate::users::User;
use crate::{Future, Github};

/// interface for statuses associated with a repository
pub struct Statuses {
    github: Github,
    owner: String,
    repo: String,
}

impl Statuses {
    #[doc(hidden)]
    pub fn new<O, R>(github: Github, owner: O, repo: R) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        Statuses {
            github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/statuses{}", self.owner, self.repo, more)
    }

    /// creates a new status for a target sha
    pub fn create(&self, sha: &str, status: &StatusOptions) -> Future<Status> {
        self.github
            .post(&self.path(&format!("/{}", sha)), json!(status))
    }

    /// lists all statuses associated with a given git sha
    pub fn list(&self, sha: &str) -> Future<Vec<Status>> {
        self.github.get(&format!(
            "/repos/{}/{}/commits/{}/statuses",
            self.owner, self.repo, sha
        ))
    }

    /// list the combined statuses for a given git sha
    /// fixme: give this a type
    pub fn combined(&self, sha: &str) -> Future<String> {
        self.github.get(&format!(
            "/repos/{}/{}/commits/{}/status",
            self.owner, self.repo, sha
        ))
    }
}

// representations (todo: replace with derive_builder)

#[derive(Debug, Deserialize)]
pub struct Status {
    pub created_at: Option<String>,
    pub updated_at: Option<String>,
    pub state: State,
    pub target_url: String,
    pub description: String,
    pub id: u64,
    pub url: String,
    pub context: String,
    pub creator: User,
}

#[derive(Debug, Default, Serialize)]
pub struct StatusOptions {
    state: State,
    #[serde(skip_serializing_if = "Option::is_none")]
    target_url: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    context: Option<String>,
}

pub struct StatusOptionsBuilder(StatusOptions);

impl StatusOptionsBuilder {
    #[doc(hidden)]
    pub(crate) fn new(state: State) -> Self {
        StatusOptionsBuilder(StatusOptions {
            state,
            ..Default::default()
        })
    }

    pub fn target_url<T>(&mut self, url: T) -> &mut Self
    where
        T: Into<String>,
    {
        self.0.target_url = Some(url.into());
        self
    }

    pub fn description<D>(&mut self, desc: D) -> &mut Self
    where
        D: Into<String>,
    {
        self.0.description = Some(desc.into());
        self
    }

    pub fn context<C>(&mut self, ctx: C) -> &mut Self
    where
        C: Into<String>,
    {
        self.0.context = Some(ctx.into());
        self
    }

    pub fn build(&self) -> StatusOptions {
        StatusOptions::new(
            self.0.state.clone(),
            self.0.target_url.clone(),
            self.0.description.clone(),
            self.0.context.clone(),
        )
    }
}

impl StatusOptions {
    #[doc(hidden)]
    pub fn new<T, D, C>(
        state: State,
        target_url: Option<T>,
        descr: Option<D>,
        context: Option<C>,
    ) -> Self
    where
        T: Into<String>,
        D: Into<String>,
        C: Into<String>,
    {
        StatusOptions {
            state,
            target_url: target_url.map(|t| t.into()),
            description: descr.map(|d| d.into()),
            context: context.map(|c| c.into()),
        }
    }

    pub fn builder(state: State) -> StatusOptionsBuilder {
        StatusOptionsBuilder::new(state)
    }
}

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum State {
    /// pending
    #[serde(rename = "pending")]
    Pending,
    /// success
    #[serde(rename = "success")]
    Success,
    /// error
    #[serde(rename = "error")]
    Error,
    /// failure
    #[serde(rename = "failure")]
    Failure,
}

impl Default for State {
    fn default() -> State {
        State::Pending
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde::ser::Serialize;
    use serde_json;

    fn test_encoding<E: Serialize>(tests: Vec<(E, &str)>) {
        for test in tests {
            match test {
                (k, v) => assert_eq!(serde_json::to_string(&k).unwrap(), v),
            }
        }
    }

    #[test]
    fn deserialize_status_state() {
        for (json, value) in vec![
            ("\"pending\"", State::Pending),
            ("\"success\"", State::Success),
            ("\"error\"", State::Error),
            ("\"failure\"", State::Failure),
        ] {
            assert_eq!(serde_json::from_str::<State>(json).unwrap(), value)
        }
    }

    #[test]
    fn serialize_status_state() {
        for (json, value) in vec![
            ("\"pending\"", State::Pending),
            ("\"success\"", State::Success),
            ("\"error\"", State::Error),
            ("\"failure\"", State::Failure),
        ] {
            assert_eq!(serde_json::to_string(&value).unwrap(), json)
        }
    }

    #[test]
    fn status_reqs() {
        let tests = vec![
            (
                StatusOptions::builder(State::Pending).build(),
                r#"{"state":"pending"}"#,
            ),
            (
                StatusOptions::builder(State::Success)
                    .target_url("http://acme.com")
                    .build(),
                r#"{"state":"success","target_url":"http://acme.com"}"#,
            ),
            (
                StatusOptions::builder(State::Error)
                    .description("desc")
                    .build(),
                r#"{"state":"error","description":"desc"}"#,
            ),
            (
                StatusOptions::builder(State::Failure)
                    .target_url("http://acme.com")
                    .description("desc")
                    .build(),
                r#"{"state":"failure","target_url":"http://acme.com","description":"desc"}"#,
            ),
        ];
        test_encoding(tests)
    }

}
<|endoftext|>


<commit_before>use crate::errors::*;
use std::convert::Into;
use std::fs::{self, File};
use std::io::Write;
use std::path::{Component, Path, PathBuf};

/// Naively replaces any path seperator with a forward-slash '/'
pub fn normalize_path(path: &str) -> String {
    use std::path::is_separator;
    path.chars()
        .map(|ch| if is_separator(ch) { '/' } else { ch })
        .collect::<String>()
}

/// Write the given data to a file, creating it first if necessary
pub fn write_file<P: AsRef<Path>>(build_dir: &Path, filename: P, content: &[u8]) -> Result<()> {
    let path = build_dir.join(filename);

    create_file(&path)?.write_all(content).map_err(Into::into)
}

/// Takes a path and returns a path containing just enough `../` to point to
/// the root of the given path.
///
/// This is mostly interesting for a relative path to point back to the
/// directory from where the path starts.
///
/// ```rust
/// # use std::path::Path;
/// # use mdbook::utils::fs::path_to_root;
/// let path = Path::new("some/relative/path");
/// assert_eq!(path_to_root(path), "../../");
/// ```
///
/// **note:** it's not very fool-proof, if you find a situation where
/// it doesn't return the correct path.
/// Consider [submitting a new issue](https://github.com/rust-lang/mdBook/issues)
/// or a [pull-request](https://github.com/rust-lang/mdBook/pulls) to improve it.
pub fn path_to_root<P: Into<PathBuf>>(path: P) -> String {
    debug!("path_to_root");
    // Remove filename and add "../" for every directory

    path.into()
        .parent()
        .expect("")
        .components()
        .fold(String::new(), |mut s, c| {
            match c {
                Component::Normal(_) => s.push_str("../"),
                _ => {
                    debug!("Other path component... {:?}", c);
                }
            }
            s
        })
}

/// This function creates a file and returns it. But before creating the file
/// it checks every directory in the path to see if it exists,
/// and if it does not it will be created.
pub fn create_file(path: &Path) -> Result<File> {
    debug!("Creating {}", path.display());

    // Construct path
    if let Some(p) = path.parent() {
        trace!("Parent directory is: {:?}", p);

        fs::create_dir_all(p)?;
    }

    File::create(path).map_err(Into::into)
}

/// Removes all the content of a directory but not the directory itself
pub fn remove_dir_content(dir: &Path) -> Result<()> {
    for item in fs::read_dir(dir)? {
        if let Ok(item) = item {
            let item = item.path();
            if item.is_dir() {
                fs::remove_dir_all(item)?;
            } else {
                fs::remove_file(item)?;
            }
        }
    }
    Ok(())
}

/// Copies all files of a directory to another one except the files
/// with the extensions given in the `ext_blacklist` array
pub fn copy_files_except_ext(
    from: &Path,
    to: &Path,
    recursive: bool,
    avoid_dir: Option<&PathBuf>,
    ext_blacklist: &[&str],
) -> Result<()> {
    debug!(
        "Copying all files from {} to {} (blacklist: {:?}), avoiding {:?}",
        from.display(),
        to.display(),
        ext_blacklist,
        avoid_dir
    );

    // Check that from and to are different
    if from == to {
        return Ok(());
    }

    for entry in fs::read_dir(from)? {
        let entry = entry?;
        let metadata = entry.path().metadata()?;

        // If the entry is a dir and the recursive option is enabled, call itself
        if metadata.is_dir() && recursive {
            if entry.path() == to.to_path_buf() {
                continue;
            }

            if let Some(avoid) = avoid_dir {
                if entry.path() == *avoid {
                    continue;
                }
            }

            // check if output dir already exists
            if !to.join(entry.file_name()).exists() {
                fs::create_dir(&to.join(entry.file_name()))?;
            }

            copy_files_except_ext(
                &from.join(entry.file_name()),
                &to.join(entry.file_name()),
                true,
                avoid_dir,
                ext_blacklist,
            )?;
        } else if metadata.is_file() {
            // Check if it is in the blacklist
            if let Some(ext) = entry.path().extension() {
                if ext_blacklist.contains(&ext.to_str().unwrap()) {
                    continue;
                }
            }
            debug!(
                "creating path for file: {:?}",
                &to.join(
                    entry
                        .path()
                        .file_name()
                        .expect("a file should have a file name...")
                )
            );

            debug!(
                "Copying {:?} to {:?}",
                entry.path(),
                &to.join(
                    entry
                        .path()
                        .file_name()
                        .expect("a file should have a file name...")
                )
            );
            fs::copy(
                entry.path(),
                &to.join(
                    entry
                        .path()
                        .file_name()
                        .expect("a file should have a file name..."),
                ),
            )?;
        }
    }
    Ok(())
}

pub fn get_404_output_file(input_404: &Option<String>) -> String {
    input_404
        .as_ref()
        .unwrap_or(&"404.md".to_string())
        .replace(".md", ".html")
}

#[cfg(test)]
mod tests {
    use super::copy_files_except_ext;
    use std::{fs, io::Result, path::Path};

    #[cfg(target_os = "windows")]
    fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Result<()> {
        std::os::window::fs::symlink_file(src, dst)
    }

    #[cfg(not(target_os = "windows"))]
    fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Result<()> {
        std::os::unix::fs::symlink(src, dst)
    }

    #[test]
    fn copy_files_except_ext_test() {
        let tmp = match tempfile::TempDir::new() {
            Ok(t) => t,
            Err(e) => panic!("Could not create a temp dir: {}", e),
        };

        // Create a couple of files
        if let Err(err) = fs::File::create(&tmp.path().join("file.txt")) {
            panic!("Could not create file.txt: {}", err);
        }
        if let Err(err) = fs::File::create(&tmp.path().join("file.md")) {
            panic!("Could not create file.md: {}", err);
        }
        if let Err(err) = fs::File::create(&tmp.path().join("file.png")) {
            panic!("Could not create file.png: {}", err);
        }
        if let Err(err) = fs::create_dir(&tmp.path().join("sub_dir")) {
            panic!("Could not create sub_dir: {}", err);
        }
        if let Err(err) = fs::File::create(&tmp.path().join("sub_dir/file.png")) {
            panic!("Could not create sub_dir/file.png: {}", err);
        }
        if let Err(err) = fs::create_dir(&tmp.path().join("sub_dir_exists")) {
            panic!("Could not create sub_dir_exists: {}", err);
        }
        if let Err(err) = fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) {
            panic!("Could not create sub_dir_exists/file.txt: {}", err);
        }
        if let Err(err) = symlink(
            &tmp.path().join("file.png"),
            &tmp.path().join("symlink.png"),
        ) {
            panic!("Could not symlink file.png: {}", err);
        }

        // Create output dir
        if let Err(err) = fs::create_dir(&tmp.path().join("output")) {
            panic!("Could not create output: {}", err);
        }
        if let Err(err) = fs::create_dir(&tmp.path().join("output/sub_dir_exists")) {
            panic!("Could not create output/sub_dir_exists: {}", err);
        }

        if let Err(e) =
            copy_files_except_ext(&tmp.path(), &tmp.path().join("output"), true, None, &["md"])
        {
            panic!("Error while executing the function:\n{:?}", e);
        }

        // Check if the correct files where created
        if !(&tmp.path().join("output/file.txt")).exists() {
            panic!("output/file.txt should exist")
        }
        if (&tmp.path().join("output/file.md")).exists() {
            panic!("output/file.md should not exist")
        }
        if !(&tmp.path().join("output/file.png")).exists() {
            panic!("output/file.png should exist")
        }
        if !(&tmp.path().join("output/sub_dir/file.png")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }
        if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }
        if !(&tmp.path().join("output/symlink.png")).exists() {
            panic!("output/symlink.png should exist")
        }
    }
}
<commit_msg>Fix windows typo<commit_after>use crate::errors::*;
use std::convert::Into;
use std::fs::{self, File};
use std::io::Write;
use std::path::{Component, Path, PathBuf};

/// Naively replaces any path seperator with a forward-slash '/'
pub fn normalize_path(path: &str) -> String {
    use std::path::is_separator;
    path.chars()
        .map(|ch| if is_separator(ch) { '/' } else { ch })
        .collect::<String>()
}

/// Write the given data to a file, creating it first if necessary
pub fn write_file<P: AsRef<Path>>(build_dir: &Path, filename: P, content: &[u8]) -> Result<()> {
    let path = build_dir.join(filename);

    create_file(&path)?.write_all(content).map_err(Into::into)
}

/// Takes a path and returns a path containing just enough `../` to point to
/// the root of the given path.
///
/// This is mostly interesting for a relative path to point back to the
/// directory from where the path starts.
///
/// ```rust
/// # use std::path::Path;
/// # use mdbook::utils::fs::path_to_root;
/// let path = Path::new("some/relative/path");
/// assert_eq!(path_to_root(path), "../../");
/// ```
///
/// **note:** it's not very fool-proof, if you find a situation where
/// it doesn't return the correct path.
/// Consider [submitting a new issue](https://github.com/rust-lang/mdBook/issues)
/// or a [pull-request](https://github.com/rust-lang/mdBook/pulls) to improve it.
pub fn path_to_root<P: Into<PathBuf>>(path: P) -> String {
    debug!("path_to_root");
    // Remove filename and add "../" for every directory

    path.into()
        .parent()
        .expect("")
        .components()
        .fold(String::new(), |mut s, c| {
            match c {
                Component::Normal(_) => s.push_str("../"),
                _ => {
                    debug!("Other path component... {:?}", c);
                }
            }
            s
        })
}

/// This function creates a file and returns it. But before creating the file
/// it checks every directory in the path to see if it exists,
/// and if it does not it will be created.
pub fn create_file(path: &Path) -> Result<File> {
    debug!("Creating {}", path.display());

    // Construct path
    if let Some(p) = path.parent() {
        trace!("Parent directory is: {:?}", p);

        fs::create_dir_all(p)?;
    }

    File::create(path).map_err(Into::into)
}

/// Removes all the content of a directory but not the directory itself
pub fn remove_dir_content(dir: &Path) -> Result<()> {
    for item in fs::read_dir(dir)? {
        if let Ok(item) = item {
            let item = item.path();
            if item.is_dir() {
                fs::remove_dir_all(item)?;
            } else {
                fs::remove_file(item)?;
            }
        }
    }
    Ok(())
}

/// Copies all files of a directory to another one except the files
/// with the extensions given in the `ext_blacklist` array
pub fn copy_files_except_ext(
    from: &Path,
    to: &Path,
    recursive: bool,
    avoid_dir: Option<&PathBuf>,
    ext_blacklist: &[&str],
) -> Result<()> {
    debug!(
        "Copying all files from {} to {} (blacklist: {:?}), avoiding {:?}",
        from.display(),
        to.display(),
        ext_blacklist,
        avoid_dir
    );

    // Check that from and to are different
    if from == to {
        return Ok(());
    }

    for entry in fs::read_dir(from)? {
        let entry = entry?;
        let metadata = entry.path().metadata()?;

        // If the entry is a dir and the recursive option is enabled, call itself
        if metadata.is_dir() && recursive {
            if entry.path() == to.to_path_buf() {
                continue;
            }

            if let Some(avoid) = avoid_dir {
                if entry.path() == *avoid {
                    continue;
                }
            }

            // check if output dir already exists
            if !to.join(entry.file_name()).exists() {
                fs::create_dir(&to.join(entry.file_name()))?;
            }

            copy_files_except_ext(
                &from.join(entry.file_name()),
                &to.join(entry.file_name()),
                true,
                avoid_dir,
                ext_blacklist,
            )?;
        } else if metadata.is_file() {
            // Check if it is in the blacklist
            if let Some(ext) = entry.path().extension() {
                if ext_blacklist.contains(&ext.to_str().unwrap()) {
                    continue;
                }
            }
            debug!(
                "creating path for file: {:?}",
                &to.join(
                    entry
                        .path()
                        .file_name()
                        .expect("a file should have a file name...")
                )
            );

            debug!(
                "Copying {:?} to {:?}",
                entry.path(),
                &to.join(
                    entry
                        .path()
                        .file_name()
                        .expect("a file should have a file name...")
                )
            );
            fs::copy(
                entry.path(),
                &to.join(
                    entry
                        .path()
                        .file_name()
                        .expect("a file should have a file name..."),
                ),
            )?;
        }
    }
    Ok(())
}

pub fn get_404_output_file(input_404: &Option<String>) -> String {
    input_404
        .as_ref()
        .unwrap_or(&"404.md".to_string())
        .replace(".md", ".html")
}

#[cfg(test)]
mod tests {
    use super::copy_files_except_ext;
    use std::{fs, io::Result, path::Path};

    #[cfg(target_os = "windows")]
    fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Result<()> {
        std::os::windows::fs::symlink_file(src, dst)
    }

    #[cfg(not(target_os = "windows"))]
    fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Result<()> {
        std::os::unix::fs::symlink(src, dst)
    }

    #[test]
    fn copy_files_except_ext_test() {
        let tmp = match tempfile::TempDir::new() {
            Ok(t) => t,
            Err(e) => panic!("Could not create a temp dir: {}", e),
        };

        // Create a couple of files
        if let Err(err) = fs::File::create(&tmp.path().join("file.txt")) {
            panic!("Could not create file.txt: {}", err);
        }
        if let Err(err) = fs::File::create(&tmp.path().join("file.md")) {
            panic!("Could not create file.md: {}", err);
        }
        if let Err(err) = fs::File::create(&tmp.path().join("file.png")) {
            panic!("Could not create file.png: {}", err);
        }
        if let Err(err) = fs::create_dir(&tmp.path().join("sub_dir")) {
            panic!("Could not create sub_dir: {}", err);
        }
        if let Err(err) = fs::File::create(&tmp.path().join("sub_dir/file.png")) {
            panic!("Could not create sub_dir/file.png: {}", err);
        }
        if let Err(err) = fs::create_dir(&tmp.path().join("sub_dir_exists")) {
            panic!("Could not create sub_dir_exists: {}", err);
        }
        if let Err(err) = fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) {
            panic!("Could not create sub_dir_exists/file.txt: {}", err);
        }
        if let Err(err) = symlink(
            &tmp.path().join("file.png"),
            &tmp.path().join("symlink.png"),
        ) {
            panic!("Could not symlink file.png: {}", err);
        }

        // Create output dir
        if let Err(err) = fs::create_dir(&tmp.path().join("output")) {
            panic!("Could not create output: {}", err);
        }
        if let Err(err) = fs::create_dir(&tmp.path().join("output/sub_dir_exists")) {
            panic!("Could not create output/sub_dir_exists: {}", err);
        }

        if let Err(e) =
            copy_files_except_ext(&tmp.path(), &tmp.path().join("output"), true, None, &["md"])
        {
            panic!("Error while executing the function:\n{:?}", e);
        }

        // Check if the correct files where created
        if !(&tmp.path().join("output/file.txt")).exists() {
            panic!("output/file.txt should exist")
        }
        if (&tmp.path().join("output/file.md")).exists() {
            panic!("output/file.md should not exist")
        }
        if !(&tmp.path().join("output/file.png")).exists() {
            panic!("output/file.png should exist")
        }
        if !(&tmp.path().join("output/sub_dir/file.png")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }
        if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }
        if !(&tmp.path().join("output/symlink.png")).exists() {
            panic!("output/symlink.png should exist")
        }
    }
}
<|endoftext|>


<commit_before>use hir::{db::AstDatabase, HirDisplay, Type};
use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
use syntax::{
    ast::{BlockExpr, ExprStmt},
    AstNode,
};
use text_edit::TextEdit;

use crate::{fix, Assist, Diagnostic, DiagnosticsContext};

// Diagnostic: type-mismatch
//
// This diagnostic is triggered when the type of an expression does not match
// the expected type.
pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic {
    let mut diag = Diagnostic::new(
        "type-mismatch",
        format!(
            "expected {}, found {}",
            d.expected.display(ctx.sema.db),
            d.actual.display(ctx.sema.db)
        ),
        ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
    )
    .with_fixes(fixes(ctx, d));
    if diag.fixes.is_none() {
        diag.experimental = true;
    }
    diag
}

fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option<Vec<Assist>> {
    let mut fixes = Vec::new();

    add_reference(ctx, d, &mut fixes);
    add_missing_ok_or_some(ctx, d, &mut fixes);
    remove_semicolon(ctx, d, &mut fixes);

    if fixes.is_empty() {
        None
    } else {
        Some(fixes)
    }
}

fn add_reference(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr_node = d.expr.value.to_node(&root);

    let range = ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range;

    let (_, mutability) = d.expected.as_reference()?;
    let actual_with_ref = Type::reference(&d.actual, mutability);
    if !actual_with_ref.could_coerce_to(ctx.sema.db, &d.expected) {
        return None;
    }

    let ampersands = format!("&{}", mutability.as_keyword_for_ref());

    let edit = TextEdit::insert(expr_node.syntax().text_range().start(), ampersands);
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
    acc.push(fix("add_reference_here", "Add reference here", source_change, range));
    Some(())
}

fn add_missing_ok_or_some(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr = d.expr.value.to_node(&root);
    let expr_range = expr.syntax().text_range();
    let scope = ctx.sema.scope(expr.syntax())?;

    let expected_adt = d.expected.as_adt()?;
    let expected_enum = expected_adt.as_enum()?;

    let famous_defs = FamousDefs(&ctx.sema, scope.krate());
    let core_result = famous_defs.core_result_Result();
    let core_option = famous_defs.core_option_Option();

    if Some(expected_enum) != core_result && Some(expected_enum) != core_option {
        return None;
    }

    let variant_name = if Some(expected_enum) == core_result { "Ok" } else { "Some" };

    let wrapped_actual_ty = expected_adt.ty_with_args(ctx.sema.db, &[d.actual.clone()]);

    if !d.expected.could_unify_with(ctx.sema.db, &wrapped_actual_ty) {
        return None;
    }

    let mut builder = TextEdit::builder();
    builder.insert(expr.syntax().text_range().start(), format!("{}(", variant_name));
    builder.insert(expr.syntax().text_range().end(), ")".to_string());
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), builder.finish());
    let name = format!("Wrap in {}", variant_name);
    acc.push(fix("wrap_in_constructor", &name, source_change, expr_range));
    Some(())
}

fn remove_semicolon(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr = d.expr.value.to_node(&root);
    if !d.actual.is_unit() {
        return None;
    }
    let block = BlockExpr::cast(expr.syntax().clone())?;
    let expr_before_semi =
        block.statements().last().and_then(|s| ExprStmt::cast(s.syntax().clone()))?;
    let type_before_semi = ctx.sema.type_of_expr(&expr_before_semi.expr()?)?.original();
    if !type_before_semi.could_coerce_to(ctx.sema.db, &d.expected) {
        return None;
    }
    let semicolon_range = expr_before_semi.semicolon_token()?.text_range();

    let edit = TextEdit::delete(semicolon_range);
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);

    acc.push(fix("remove_semicolon", "Remove this semicolon", source_change, semicolon_range));
    Some(())
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_diagnostics, check_fix, check_no_fix};

    #[test]
    fn missing_reference() {
        check_diagnostics(
            r#"
fn main() {
    test(123);
       //^^^ 💡 error: expected &i32, found i32
}
fn test(arg: &i32) {}
"#,
        );
    }

    #[test]
    fn test_add_reference_to_int() {
        check_fix(
            r#"
fn main() {
    test(123$0);
}
fn test(arg: &i32) {}
            "#,
            r#"
fn main() {
    test(&123);
}
fn test(arg: &i32) {}
            "#,
        );
    }

    #[test]
    fn test_add_mutable_reference_to_int() {
        check_fix(
            r#"
fn main() {
    test($0123);
}
fn test(arg: &mut i32) {}
            "#,
            r#"
fn main() {
    test(&mut 123);
}
fn test(arg: &mut i32) {}
            "#,
        );
    }

    #[test]
    fn test_add_reference_to_array() {
        check_fix(
            r#"
//- minicore: coerce_unsized
fn main() {
    test($0[1, 2, 3]);
}
fn test(arg: &[i32]) {}
            "#,
            r#"
fn main() {
    test(&[1, 2, 3]);
}
fn test(arg: &[i32]) {}
            "#,
        );
    }

    #[test]
    fn test_add_reference_with_autoderef() {
        check_fix(
            r#"
//- minicore: coerce_unsized, deref
struct Foo;
struct Bar;
impl core::ops::Deref for Foo {
    type Target = Bar;
}

fn main() {
    test($0Foo);
}
fn test(arg: &Bar) {}
            "#,
            r#"
struct Foo;
struct Bar;
impl core::ops::Deref for Foo {
    type Target = Bar;
}

fn main() {
    test(&Foo);
}
fn test(arg: &Bar) {}
            "#,
        );
    }

    #[test]
    fn test_add_reference_to_method_call() {
        check_fix(
            r#"
fn main() {
    Test.call_by_ref($0123);
}
struct Test;
impl Test {
    fn call_by_ref(&self, arg: &i32) {}
}
            "#,
            r#"
fn main() {
    Test.call_by_ref(&123);
}
struct Test;
impl Test {
    fn call_by_ref(&self, arg: &i32) {}
}
            "#,
        );
    }

    #[test]
    fn test_add_reference_to_let_stmt() {
        check_fix(
            r#"
fn main() {
    let test: &i32 = $0123;
}
            "#,
            r#"
fn main() {
    let test: &i32 = &123;
}
            "#,
        );
    }

    #[test]
    fn test_add_mutable_reference_to_let_stmt() {
        check_fix(
            r#"
fn main() {
    let test: &mut i32 = $0123;
}
            "#,
            r#"
fn main() {
    let test: &mut i32 = &mut 123;
}
            "#,
        );
    }

    #[test]
    fn test_wrap_return_type_option() {
        check_fix(
            r#"
//- minicore: option, result
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        return None;
    }
    x / y$0
}
"#,
            r#"
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        return None;
    }
    Some(x / y)
}
"#,
        );
    }

    #[test]
    fn const_generic_type_mismatch() {
        check_diagnostics(
            r#"
            pub struct Rate<const N: u32>;
            fn f<const N: u64>() -> Rate<N> { // FIXME: add some error
                loop {}
            }
            fn run(t: Rate<5>) {
            }
            fn main() {
                run(f()) // FIXME: remove this error
                  //^^^ error: expected Rate<5>, found Rate<_>
            }
"#,
        );
    }

    #[test]
    fn const_generic_unknown() {
        check_diagnostics(
            r#"
            pub struct Rate<T, const NOM: u32, const DENOM: u32>(T);
            fn run(t: Rate<u32, 1, 1>) {
            }
            fn main() {
                run(Rate::<_, _, _>(5));
            }
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_option_tails() {
        check_fix(
            r#"
//- minicore: option, result
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        Some(0)
    } else if true {
        100$0
    } else {
        None
    }
}
"#,
            r#"
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        Some(0)
    } else if true {
        Some(100)
    } else {
        None
    }
}
"#,
        );
    }

    #[test]
    fn test_wrap_return_type() {
        check_fix(
            r#"
//- minicore: option, result
fn div(x: i32, y: i32) -> Result<i32, ()> {
    if y == 0 {
        return Err(());
    }
    x / y$0
}
"#,
            r#"
fn div(x: i32, y: i32) -> Result<i32, ()> {
    if y == 0 {
        return Err(());
    }
    Ok(x / y)
}
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_handles_generic_functions() {
        check_fix(
            r#"
//- minicore: option, result
fn div<T>(x: T) -> Result<T, i32> {
    if x == 0 {
        return Err(7);
    }
    $0x
}
"#,
            r#"
fn div<T>(x: T) -> Result<T, i32> {
    if x == 0 {
        return Err(7);
    }
    Ok(x)
}
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_handles_type_aliases() {
        check_fix(
            r#"
//- minicore: option, result
type MyResult<T> = Result<T, ()>;

fn div(x: i32, y: i32) -> MyResult<i32> {
    if y == 0 {
        return Err(());
    }
    x $0/ y
}
"#,
            r#"
type MyResult<T> = Result<T, ()>;

fn div(x: i32, y: i32) -> MyResult<i32> {
    if y == 0 {
        return Err(());
    }
    Ok(x / y)
}
"#,
        );
    }

    #[test]
    fn test_in_const_and_static() {
        check_fix(
            r#"
//- minicore: option, result
static A: Option<()> = {($0)};
            "#,
            r#"
static A: Option<()> = {Some(())};
            "#,
        );
        check_fix(
            r#"
//- minicore: option, result
const _: Option<()> = {($0)};
            "#,
            r#"
const _: Option<()> = {Some(())};
            "#,
        );
    }

    #[test]
    fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
        check_no_fix(
            r#"
//- minicore: option, result
fn foo() -> Result<(), i32> { 0$0 }
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
        check_no_fix(
            r#"
//- minicore: option, result
enum SomeOtherEnum { Ok(i32), Err(String) }

fn foo() -> SomeOtherEnum { 0$0 }
"#,
        );
    }

    #[test]
    fn remove_semicolon() {
        check_fix(r#"fn f() -> i32 { 92$0; }"#, r#"fn f() -> i32 { 92 }"#);
    }
}
<commit_msg>Add str_ref_to_string fix<commit_after>use hir::{db::AstDatabase, HirDisplay, Type};
use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
use syntax::{
    ast::{BlockExpr, ExprStmt},
    AstNode,
};
use text_edit::TextEdit;

use crate::{fix, Assist, Diagnostic, DiagnosticsContext};

// Diagnostic: type-mismatch
//
// This diagnostic is triggered when the type of an expression does not match
// the expected type.
pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic {
    let mut diag = Diagnostic::new(
        "type-mismatch",
        format!(
            "expected {}, found {}",
            d.expected.display(ctx.sema.db),
            d.actual.display(ctx.sema.db)
        ),
        ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
    )
    .with_fixes(fixes(ctx, d));
    if diag.fixes.is_none() {
        diag.experimental = true;
    }
    diag
}

fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option<Vec<Assist>> {
    let mut fixes = Vec::new();

    add_reference(ctx, d, &mut fixes);
    add_missing_ok_or_some(ctx, d, &mut fixes);
    remove_semicolon(ctx, d, &mut fixes);
    str_ref_to_string(ctx, d, &mut fixes);

    if fixes.is_empty() {
        None
    } else {
        Some(fixes)
    }
}

fn add_reference(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr_node = d.expr.value.to_node(&root);

    let range = ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range;

    let (_, mutability) = d.expected.as_reference()?;
    let actual_with_ref = Type::reference(&d.actual, mutability);
    if !actual_with_ref.could_coerce_to(ctx.sema.db, &d.expected) {
        return None;
    }

    let ampersands = format!("&{}", mutability.as_keyword_for_ref());

    let edit = TextEdit::insert(expr_node.syntax().text_range().start(), ampersands);
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
    acc.push(fix("add_reference_here", "Add reference here", source_change, range));
    Some(())
}

fn add_missing_ok_or_some(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr = d.expr.value.to_node(&root);
    let expr_range = expr.syntax().text_range();
    let scope = ctx.sema.scope(expr.syntax())?;

    let expected_adt = d.expected.as_adt()?;
    let expected_enum = expected_adt.as_enum()?;

    let famous_defs = FamousDefs(&ctx.sema, scope.krate());
    let core_result = famous_defs.core_result_Result();
    let core_option = famous_defs.core_option_Option();

    if Some(expected_enum) != core_result && Some(expected_enum) != core_option {
        return None;
    }

    let variant_name = if Some(expected_enum) == core_result { "Ok" } else { "Some" };

    let wrapped_actual_ty = expected_adt.ty_with_args(ctx.sema.db, &[d.actual.clone()]);

    if !d.expected.could_unify_with(ctx.sema.db, &wrapped_actual_ty) {
        return None;
    }

    let mut builder = TextEdit::builder();
    builder.insert(expr.syntax().text_range().start(), format!("{}(", variant_name));
    builder.insert(expr.syntax().text_range().end(), ")".to_string());
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), builder.finish());
    let name = format!("Wrap in {}", variant_name);
    acc.push(fix("wrap_in_constructor", &name, source_change, expr_range));
    Some(())
}

fn remove_semicolon(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr = d.expr.value.to_node(&root);
    if !d.actual.is_unit() {
        return None;
    }
    let block = BlockExpr::cast(expr.syntax().clone())?;
    let expr_before_semi =
        block.statements().last().and_then(|s| ExprStmt::cast(s.syntax().clone()))?;
    let type_before_semi = ctx.sema.type_of_expr(&expr_before_semi.expr()?)?.original();
    if !type_before_semi.could_coerce_to(ctx.sema.db, &d.expected) {
        return None;
    }
    let semicolon_range = expr_before_semi.semicolon_token()?.text_range();

    let edit = TextEdit::delete(semicolon_range);
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);

    acc.push(fix("remove_semicolon", "Remove this semicolon", source_change, semicolon_range));
    Some(())
}

fn str_ref_to_string(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let expected = d.expected.display(ctx.sema.db);
    let actual = d.actual.display(ctx.sema.db);

    if expected.to_string() != "String" || actual.to_string() != "&str" {
        return None;
    }

    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr = d.expr.value.to_node(&root);
    let expr_range = expr.syntax().text_range();

    let to_string = format!(".to_string()");

    let edit = TextEdit::insert(expr.syntax().text_range().end(), to_string);
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
    acc.push(fix("str_ref_to_string", "Use to_string() here", source_change, expr_range));

    Some(())
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_diagnostics, check_fix, check_no_fix};

    #[test]
    fn missing_reference() {
        check_diagnostics(
            r#"
fn main() {
    test(123);
       //^^^ 💡 error: expected &i32, found i32
}
fn test(arg: &i32) {}
"#,
        );
    }

    #[test]
    fn test_add_reference_to_int() {
        check_fix(
            r#"
fn main() {
    test(123$0);
}
fn test(arg: &i32) {}
            "#,
            r#"
fn main() {
    test(&123);
}
fn test(arg: &i32) {}
            "#,
        );
    }

    #[test]
    fn test_add_mutable_reference_to_int() {
        check_fix(
            r#"
fn main() {
    test($0123);
}
fn test(arg: &mut i32) {}
            "#,
            r#"
fn main() {
    test(&mut 123);
}
fn test(arg: &mut i32) {}
            "#,
        );
    }

    #[test]
    fn test_add_reference_to_array() {
        check_fix(
            r#"
//- minicore: coerce_unsized
fn main() {
    test($0[1, 2, 3]);
}
fn test(arg: &[i32]) {}
            "#,
            r#"
fn main() {
    test(&[1, 2, 3]);
}
fn test(arg: &[i32]) {}
            "#,
        );
    }

    #[test]
    fn test_add_reference_with_autoderef() {
        check_fix(
            r#"
//- minicore: coerce_unsized, deref
struct Foo;
struct Bar;
impl core::ops::Deref for Foo {
    type Target = Bar;
}

fn main() {
    test($0Foo);
}
fn test(arg: &Bar) {}
            "#,
            r#"
struct Foo;
struct Bar;
impl core::ops::Deref for Foo {
    type Target = Bar;
}

fn main() {
    test(&Foo);
}
fn test(arg: &Bar) {}
            "#,
        );
    }

    #[test]
    fn test_add_reference_to_method_call() {
        check_fix(
            r#"
fn main() {
    Test.call_by_ref($0123);
}
struct Test;
impl Test {
    fn call_by_ref(&self, arg: &i32) {}
}
            "#,
            r#"
fn main() {
    Test.call_by_ref(&123);
}
struct Test;
impl Test {
    fn call_by_ref(&self, arg: &i32) {}
}
            "#,
        );
    }

    #[test]
    fn test_add_reference_to_let_stmt() {
        check_fix(
            r#"
fn main() {
    let test: &i32 = $0123;
}
            "#,
            r#"
fn main() {
    let test: &i32 = &123;
}
            "#,
        );
    }

    #[test]
    fn test_add_mutable_reference_to_let_stmt() {
        check_fix(
            r#"
fn main() {
    let test: &mut i32 = $0123;
}
            "#,
            r#"
fn main() {
    let test: &mut i32 = &mut 123;
}
            "#,
        );
    }

    #[test]
    fn test_wrap_return_type_option() {
        check_fix(
            r#"
//- minicore: option, result
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        return None;
    }
    x / y$0
}
"#,
            r#"
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        return None;
    }
    Some(x / y)
}
"#,
        );
    }

    #[test]
    fn const_generic_type_mismatch() {
        check_diagnostics(
            r#"
            pub struct Rate<const N: u32>;
            fn f<const N: u64>() -> Rate<N> { // FIXME: add some error
                loop {}
            }
            fn run(t: Rate<5>) {
            }
            fn main() {
                run(f()) // FIXME: remove this error
                  //^^^ error: expected Rate<5>, found Rate<_>
            }
"#,
        );
    }

    #[test]
    fn const_generic_unknown() {
        check_diagnostics(
            r#"
            pub struct Rate<T, const NOM: u32, const DENOM: u32>(T);
            fn run(t: Rate<u32, 1, 1>) {
            }
            fn main() {
                run(Rate::<_, _, _>(5));
            }
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_option_tails() {
        check_fix(
            r#"
//- minicore: option, result
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        Some(0)
    } else if true {
        100$0
    } else {
        None
    }
}
"#,
            r#"
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        Some(0)
    } else if true {
        Some(100)
    } else {
        None
    }
}
"#,
        );
    }

    #[test]
    fn test_wrap_return_type() {
        check_fix(
            r#"
//- minicore: option, result
fn div(x: i32, y: i32) -> Result<i32, ()> {
    if y == 0 {
        return Err(());
    }
    x / y$0
}
"#,
            r#"
fn div(x: i32, y: i32) -> Result<i32, ()> {
    if y == 0 {
        return Err(());
    }
    Ok(x / y)
}
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_handles_generic_functions() {
        check_fix(
            r#"
//- minicore: option, result
fn div<T>(x: T) -> Result<T, i32> {
    if x == 0 {
        return Err(7);
    }
    $0x
}
"#,
            r#"
fn div<T>(x: T) -> Result<T, i32> {
    if x == 0 {
        return Err(7);
    }
    Ok(x)
}
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_handles_type_aliases() {
        check_fix(
            r#"
//- minicore: option, result
type MyResult<T> = Result<T, ()>;

fn div(x: i32, y: i32) -> MyResult<i32> {
    if y == 0 {
        return Err(());
    }
    x $0/ y
}
"#,
            r#"
type MyResult<T> = Result<T, ()>;

fn div(x: i32, y: i32) -> MyResult<i32> {
    if y == 0 {
        return Err(());
    }
    Ok(x / y)
}
"#,
        );
    }

    #[test]
    fn test_in_const_and_static() {
        check_fix(
            r#"
//- minicore: option, result
static A: Option<()> = {($0)};
            "#,
            r#"
static A: Option<()> = {Some(())};
            "#,
        );
        check_fix(
            r#"
//- minicore: option, result
const _: Option<()> = {($0)};
            "#,
            r#"
const _: Option<()> = {Some(())};
            "#,
        );
    }

    #[test]
    fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
        check_no_fix(
            r#"
//- minicore: option, result
fn foo() -> Result<(), i32> { 0$0 }
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
        check_no_fix(
            r#"
//- minicore: option, result
enum SomeOtherEnum { Ok(i32), Err(String) }

fn foo() -> SomeOtherEnum { 0$0 }
"#,
        );
    }

    #[test]
    fn remove_semicolon() {
        check_fix(r#"fn f() -> i32 { 92$0; }"#, r#"fn f() -> i32 { 92 }"#);
    }

    #[test]
    fn str_ref_to_string() {
        check_fix(
            r#"
fn test() -> String {
    "a"$0
}
            "#,
            r#"
fn test() -> String {
    "a".to_string()
}
            "#,
        );
    }
}
<|endoftext|>


<commit_before>use crate::syntax::atom::Atom::{self, *};
use crate::syntax::{error, ident, Api, ExternFn, Lang, Ref, Slice, Struct, Ty1, Type, Types};
use proc_macro2::{Delimiter, Group, Ident, TokenStream};
use quote::{quote, ToTokens};
use std::fmt::Display;
use syn::{Error, Result};

struct Check<'a> {
    apis: &'a [Api],
    types: &'a Types<'a>,
    errors: &'a mut Vec<Error>,
}

pub(crate) fn typecheck(apis: &[Api], types: &Types) -> Result<()> {
    let mut errors = Vec::new();
    let mut cx = Check {
        apis,
        types,
        errors: &mut errors,
    };
    do_typecheck(&mut cx);
    combine_errors(errors)
}

fn do_typecheck(cx: &mut Check) {
    for ty in cx.types {
        match ty {
            Type::Ident(ident) => check_type_ident(cx, ident),
            Type::RustBox(ptr) => check_type_box(cx, ptr),
            Type::UniquePtr(ptr) => check_type_unique_ptr(cx, ptr),
            Type::Ref(ty) => check_type_ref(cx, ty),
            Type::Slice(ty) => check_type_slice(cx, ty),
            _ => {}
        }
    }

    for api in cx.apis {
        match api {
            Api::Struct(strct) => check_api_struct(cx, strct),
            Api::CxxFunction(efn) | Api::RustFunction(efn) => check_api_fn(cx, efn),
            _ => {}
        }
    }

    for api in cx.apis {
        if let Api::CxxFunction(efn) = api {
            check_mut_return_restriction(cx, efn);
        }
        if let Api::CxxFunction(efn) | Api::RustFunction(efn) = api {
            check_multiple_arg_lifetimes(cx, efn);
        }
    }

    ident::check_all(cx.apis, cx.errors);
}

impl Check<'_> {
    fn error(&mut self, sp: impl ToTokens, msg: impl Display) {
        self.errors.push(Error::new_spanned(sp, msg));
    }
}

fn check_type_ident(cx: &mut Check, ident: &Ident) {
    if Atom::from(ident).is_none()
        && !cx.types.structs.contains_key(ident)
        && !cx.types.cxx.contains(ident)
        && !cx.types.rust.contains(ident)
    {
        cx.error(ident, "unsupported type");
    }
}

fn check_type_box(cx: &mut Check, ptr: &Ty1) {
    if let Type::Ident(ident) = &ptr.inner {
        if cx.types.cxx.contains(ident) {
            cx.error(ptr, error::BOX_CXX_TYPE.msg);
        }

        if Atom::from(ident).is_none() {
            return;
        }
    }

    cx.error(ptr, "unsupported target type of Box");
}

fn check_type_unique_ptr(cx: &mut Check, ptr: &Ty1) {
    if let Type::Ident(ident) = &ptr.inner {
        if cx.types.rust.contains(ident) {
            cx.error(ptr, "unique_ptr of a Rust type is not supported yet");
        }

        match Atom::from(ident) {
            None | Some(CxxString) => return,
            _ => {}
        }
    }

    cx.error(ptr, "unsupported unique_ptr target type");
}

fn check_type_ref(cx: &mut Check, ty: &Ref) {
    match ty.inner {
        Type::Fn(_) | Type::Void(_) => {}
        _ => return,
    }

    cx.error(ty, "unsupported reference type");
}

fn check_type_slice(cx: &mut Check, ty: &Slice) {
    cx.error(ty, "only &[u8] is supported so far, not other slice types");
}

fn check_api_struct(cx: &mut Check, strct: &Struct) {
    if strct.fields.is_empty() {
        let span = span_for_struct_error(strct);
        cx.error(span, "structs without any fields are not supported");
    }

    for field in &strct.fields {
        if is_unsized(cx, &field.ty) {
            let desc = describe(cx, &field.ty);
            let msg = format!("using {} by value is not supported", desc);
            cx.error(field, msg);
        }
        if let Type::Fn(_) = field.ty {
            cx.error(
                field,
                "function pointers in a struct field are not implemented yet",
            );
        }
    }
}

fn check_api_fn(cx: &mut Check, efn: &ExternFn) {
    for arg in &efn.args {
        if is_unsized(cx, &arg.ty) {
            let desc = describe(cx, &arg.ty);
            let msg = format!("passing {} by value is not supported", desc);
            cx.error(arg, msg);
        }
        if let Type::Fn(_) = arg.ty {
            if efn.lang == Lang::Rust {
                cx.error(
                    arg,
                    "passing a function pointer from C++ to Rust is not implemented yet",
                );
            }
        }
    }

    if let Some(ty) = &efn.ret {
        if is_unsized(cx, ty) {
            let desc = describe(cx, ty);
            let msg = format!("returning {} by value is not supported", desc);
            cx.error(ty, msg);
        }
        if let Type::Fn(_) = ty {
            cx.error(ty, "returning a function pointer is not implemented yet");
        }
    }
}

fn check_mut_return_restriction(cx: &mut Check, efn: &ExternFn) {
    match &efn.ret {
        Some(Type::Ref(ty)) if ty.mutability.is_some() => {}
        _ => return,
    }

    for arg in &efn.args {
        if let Type::Ref(ty) = &arg.ty {
            if ty.mutability.is_some() {
                return;
            }
        }
    }

    cx.error(
        efn,
        "&mut return type is not allowed unless there is a &mut argument",
    );
}

fn check_multiple_arg_lifetimes(cx: &mut Check, efn: &ExternFn) {
    match &efn.ret {
        Some(Type::Ref(_)) => {}
        _ => return,
    }

    let mut reference_args = 0;
    for arg in &efn.args {
        if let Type::Ref(_) = &arg.ty {
            reference_args += 1;
        }
    }

    if efn.receiver.is_some() {
        reference_args += 1;
    }

    if reference_args != 1 {
        cx.error(
            efn,
            "functions that return a reference must take exactly one input reference",
        );
    }
}

fn is_unsized(cx: &mut Check, ty: &Type) -> bool {
    let ident = match ty {
        Type::Ident(ident) => ident,
        Type::Slice(_) | Type::Void(_) => return true,
        _ => return false,
    };
    ident == CxxString || cx.types.cxx.contains(ident) || cx.types.rust.contains(ident)
}

fn span_for_struct_error(strct: &Struct) -> TokenStream {
    let struct_token = strct.struct_token;
    let mut brace_token = Group::new(Delimiter::Brace, TokenStream::new());
    brace_token.set_span(strct.brace_token.span);
    quote!(#struct_token #brace_token)
}

fn combine_errors(errors: Vec<Error>) -> Result<()> {
    let mut iter = errors.into_iter();
    let mut all_errors = match iter.next() {
        Some(err) => err,
        None => return Ok(()),
    };
    for err in iter {
        all_errors.combine(err);
    }
    Err(all_errors)
}

fn describe(cx: &mut Check, ty: &Type) -> String {
    match ty {
        Type::Ident(ident) => {
            if cx.types.structs.contains_key(ident) {
                "struct".to_owned()
            } else if cx.types.cxx.contains(ident) {
                "C++ type".to_owned()
            } else if cx.types.rust.contains(ident) {
                "opaque Rust type".to_owned()
            } else if Atom::from(ident) == Some(CxxString) {
                "C++ string".to_owned()
            } else {
                ident.to_string()
            }
        }
        Type::RustBox(_) => "Box".to_owned(),
        Type::UniquePtr(_) => "unique_ptr".to_owned(),
        Type::Ref(_) => "reference".to_owned(),
        Type::Str(_) => "&str".to_owned(),
        Type::Slice(_) => "slice".to_owned(),
        Type::SliceRefU8(_) => "&[u8]".to_owned(),
        Type::Fn(_) => "function pointer".to_owned(),
        Type::Void(_) => "()".to_owned(),
    }
}
<commit_msg>Reject explicit lifetimes in a reference type<commit_after>use crate::syntax::atom::Atom::{self, *};
use crate::syntax::{
    error, ident, Api, ExternFn, Lang, Receiver, Ref, Slice, Struct, Ty1, Type, Types,
};
use proc_macro2::{Delimiter, Group, Ident, TokenStream};
use quote::{quote, ToTokens};
use std::fmt::Display;
use syn::{Error, Result};

struct Check<'a> {
    apis: &'a [Api],
    types: &'a Types<'a>,
    errors: &'a mut Vec<Error>,
}

pub(crate) fn typecheck(apis: &[Api], types: &Types) -> Result<()> {
    let mut errors = Vec::new();
    let mut cx = Check {
        apis,
        types,
        errors: &mut errors,
    };
    do_typecheck(&mut cx);
    combine_errors(errors)
}

fn do_typecheck(cx: &mut Check) {
    for ty in cx.types {
        match ty {
            Type::Ident(ident) => check_type_ident(cx, ident),
            Type::RustBox(ptr) => check_type_box(cx, ptr),
            Type::UniquePtr(ptr) => check_type_unique_ptr(cx, ptr),
            Type::Ref(ty) => check_type_ref(cx, ty),
            Type::Slice(ty) => check_type_slice(cx, ty),
            _ => {}
        }
    }

    for api in cx.apis {
        match api {
            Api::Struct(strct) => check_api_struct(cx, strct),
            Api::CxxFunction(efn) | Api::RustFunction(efn) => check_api_fn(cx, efn),
            _ => {}
        }
    }

    for api in cx.apis {
        if let Api::CxxFunction(efn) = api {
            check_mut_return_restriction(cx, efn);
        }
        if let Api::CxxFunction(efn) | Api::RustFunction(efn) = api {
            check_multiple_arg_lifetimes(cx, efn);
        }
    }

    ident::check_all(cx.apis, cx.errors);
}

impl Check<'_> {
    fn error(&mut self, sp: impl ToTokens, msg: impl Display) {
        self.errors.push(Error::new_spanned(sp, msg));
    }
}

fn check_type_ident(cx: &mut Check, ident: &Ident) {
    if Atom::from(ident).is_none()
        && !cx.types.structs.contains_key(ident)
        && !cx.types.cxx.contains(ident)
        && !cx.types.rust.contains(ident)
    {
        cx.error(ident, "unsupported type");
    }
}

fn check_type_box(cx: &mut Check, ptr: &Ty1) {
    if let Type::Ident(ident) = &ptr.inner {
        if cx.types.cxx.contains(ident) {
            cx.error(ptr, error::BOX_CXX_TYPE.msg);
        }

        if Atom::from(ident).is_none() {
            return;
        }
    }

    cx.error(ptr, "unsupported target type of Box");
}

fn check_type_unique_ptr(cx: &mut Check, ptr: &Ty1) {
    if let Type::Ident(ident) = &ptr.inner {
        if cx.types.rust.contains(ident) {
            cx.error(ptr, "unique_ptr of a Rust type is not supported yet");
        }

        match Atom::from(ident) {
            None | Some(CxxString) => return,
            _ => {}
        }
    }

    cx.error(ptr, "unsupported unique_ptr target type");
}

fn check_type_ref(cx: &mut Check, ty: &Ref) {
    if ty.lifetime.is_some() {
        cx.error(ty, "references with explicit lifetimes are not supported");
    }

    match ty.inner {
        Type::Fn(_) | Type::Void(_) => {}
        _ => return,
    }

    cx.error(ty, "unsupported reference type");
}

fn check_type_slice(cx: &mut Check, ty: &Slice) {
    cx.error(ty, "only &[u8] is supported so far, not other slice types");
}

fn check_api_struct(cx: &mut Check, strct: &Struct) {
    if strct.fields.is_empty() {
        let span = span_for_struct_error(strct);
        cx.error(span, "structs without any fields are not supported");
    }

    for field in &strct.fields {
        if is_unsized(cx, &field.ty) {
            let desc = describe(cx, &field.ty);
            let msg = format!("using {} by value is not supported", desc);
            cx.error(field, msg);
        }
        if let Type::Fn(_) = field.ty {
            cx.error(
                field,
                "function pointers in a struct field are not implemented yet",
            );
        }
    }
}

fn check_api_fn(cx: &mut Check, efn: &ExternFn) {
    if let Some(receiver) = &efn.receiver {
        if receiver.lifetime.is_some() {
            let span = span_for_receiver_error(receiver);
            cx.error(span, "references with explicit lifetimes are not supported");
        }
    }

    for arg in &efn.args {
        if is_unsized(cx, &arg.ty) {
            let desc = describe(cx, &arg.ty);
            let msg = format!("passing {} by value is not supported", desc);
            cx.error(arg, msg);
        }
        if let Type::Fn(_) = arg.ty {
            if efn.lang == Lang::Rust {
                cx.error(
                    arg,
                    "passing a function pointer from C++ to Rust is not implemented yet",
                );
            }
        }
    }

    if let Some(ty) = &efn.ret {
        if is_unsized(cx, ty) {
            let desc = describe(cx, ty);
            let msg = format!("returning {} by value is not supported", desc);
            cx.error(ty, msg);
        }
        if let Type::Fn(_) = ty {
            cx.error(ty, "returning a function pointer is not implemented yet");
        }
    }
}

fn check_mut_return_restriction(cx: &mut Check, efn: &ExternFn) {
    match &efn.ret {
        Some(Type::Ref(ty)) if ty.mutability.is_some() => {}
        _ => return,
    }

    for arg in &efn.args {
        if let Type::Ref(ty) = &arg.ty {
            if ty.mutability.is_some() {
                return;
            }
        }
    }

    cx.error(
        efn,
        "&mut return type is not allowed unless there is a &mut argument",
    );
}

fn check_multiple_arg_lifetimes(cx: &mut Check, efn: &ExternFn) {
    match &efn.ret {
        Some(Type::Ref(_)) => {}
        _ => return,
    }

    let mut reference_args = 0;
    for arg in &efn.args {
        if let Type::Ref(_) = &arg.ty {
            reference_args += 1;
        }
    }

    if efn.receiver.is_some() {
        reference_args += 1;
    }

    if reference_args != 1 {
        cx.error(
            efn,
            "functions that return a reference must take exactly one input reference",
        );
    }
}

fn is_unsized(cx: &mut Check, ty: &Type) -> bool {
    let ident = match ty {
        Type::Ident(ident) => ident,
        Type::Slice(_) | Type::Void(_) => return true,
        _ => return false,
    };
    ident == CxxString || cx.types.cxx.contains(ident) || cx.types.rust.contains(ident)
}

fn span_for_struct_error(strct: &Struct) -> TokenStream {
    let struct_token = strct.struct_token;
    let mut brace_token = Group::new(Delimiter::Brace, TokenStream::new());
    brace_token.set_span(strct.brace_token.span);
    quote!(#struct_token #brace_token)
}

fn span_for_receiver_error(receiver: &Receiver) -> TokenStream {
    let ampersand = receiver.ampersand;
    let lifetime = &receiver.lifetime;
    let mutability = receiver.mutability;
    if receiver.shorthand {
        let var = receiver.var;
        quote!(#ampersand #lifetime #mutability #var)
    } else {
        let ty = &receiver.ty;
        quote!(#ampersand #lifetime #mutability #ty)
    }
}

fn combine_errors(errors: Vec<Error>) -> Result<()> {
    let mut iter = errors.into_iter();
    let mut all_errors = match iter.next() {
        Some(err) => err,
        None => return Ok(()),
    };
    for err in iter {
        all_errors.combine(err);
    }
    Err(all_errors)
}

fn describe(cx: &mut Check, ty: &Type) -> String {
    match ty {
        Type::Ident(ident) => {
            if cx.types.structs.contains_key(ident) {
                "struct".to_owned()
            } else if cx.types.cxx.contains(ident) {
                "C++ type".to_owned()
            } else if cx.types.rust.contains(ident) {
                "opaque Rust type".to_owned()
            } else if Atom::from(ident) == Some(CxxString) {
                "C++ string".to_owned()
            } else {
                ident.to_string()
            }
        }
        Type::RustBox(_) => "Box".to_owned(),
        Type::UniquePtr(_) => "unique_ptr".to_owned(),
        Type::Ref(_) => "reference".to_owned(),
        Type::Str(_) => "&str".to_owned(),
        Type::Slice(_) => "slice".to_owned(),
        Type::SliceRefU8(_) => "&[u8]".to_owned(),
        Type::Fn(_) => "function pointer".to_owned(),
        Type::Void(_) => "()".to_owned(),
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;

extern crate bytes;
extern crate tokio;
extern crate tokio_codec;
extern crate tokio_io;

extern crate serde;
extern crate serde_json;

use bytes::BytesMut;
use std::io;
use tokio::codec::{Encoder,Decoder};
use tokio::prelude::*;
use tokio::net::TcpListener;
use std::collections::HashMap;
use std::sync::{Mutex, Arc};

#[derive(Clone,Copy)]
pub struct ExampleJSONParser;
impl ExampleJSONParser {
    fn new() -> ExampleJSONParser {
        ExampleJSONParser{}
    }
}

impl ExampleJSONParser {
    fn parse(&self, info: &Vec<u8>)  -> Message {
        let vec_to_parse = info.clone();
        let message = String::from_utf8(vec_to_parse).unwrap();
        println!("Json parser for: {:?}", message);
        let msg: Message = match serde_json::from_str(&message)  {
            Err(..) =>   {println!("It was not parsed correctly"); Message::new_empty() },
            Ok(msg) => msg,
        };
        return msg
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Message {
    operation: String,
}

impl Message {
    fn new(operation: String) -> Message {
        Message {operation: operation}
    }
    fn new_empty() -> Message  {
        Message {operation: "".to_string()}
    }

}
pub trait Operation {
}

pub struct MyBytesCodec {
    json_parser: ExampleJSONParser,
    operations: HashMap<String, Arc<Mutex<dyn Operation + Send + 'static>>>,
    //operations: HashMap<String, Box<dyn Operation + Send>>,
}

impl MyBytesCodec {
    fn new() -> MyBytesCodec {
        MyBytesCodec{json_parser: ExampleJSONParser::new(), operations: HashMap::new()}
    }
}

impl Decoder for MyBytesCodec {
    type Item = Message;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<Message>> {
        if buf.len() == 0 {
            return Ok(None);
        }
        let data = buf.clone().to_vec();
        let cloned_data = data.clone();
        let parsed = self.json_parser.parse(&cloned_data);
        buf.clear();
        Ok(Some(parsed))
    }
}

impl Encoder for MyBytesCodec {
    type Item = Message;
    type Error = io::Error;

    fn encode(&mut self, data: Message, buf: &mut BytesMut) -> io::Result<()> {
        buf.extend(serde_json::to_string(&data)?.into_bytes());
        Ok(())
    }
}

fn main() {
    let addr = "127.0.0.1:12345".parse().unwrap();
    let listener = TcpListener::bind(&addr).expect("unable to bind TCP listener");
    let server = listener.incoming()
            .map_err(|e| eprintln!("accept failed = {:?}", e))
            .for_each(move |socket| {
                let framed = MyBytesCodec::new().framed(socket);
                let (_writer, reader) = framed.split();

                /* function to handle connection  */
                let handle_conn = reader.for_each(|message| {
                    println!("my parsed message!!: {:?}", serde_json::to_string(&message));
                    Ok(())
                })
                .and_then(|()| {
                    println!("Socket received FIN packet and closed connection");
                    Ok(())
                })
                .or_else(|err| {
                    println!("Socked closed with error: {:?}", err);
                    Err(err)

                })
                .then(|result| {
                    println!("Socket closed with result: {:?}", result);
                    Ok(())
                });

            tokio::spawn(handle_conn)
    });
    tokio::run(server);
}

<commit_msg>Fixed error to apply traits<commit_after>#[macro_use]
extern crate serde_derive;

extern crate bytes;
extern crate tokio;
extern crate tokio_codec;
extern crate tokio_io;

extern crate serde;
extern crate serde_json;

use bytes::BytesMut;
use std::io;
use tokio::codec::{Encoder,Decoder};
use tokio::prelude::*;
use tokio::net::TcpListener;
use std::collections::HashMap;
use std::sync::{Mutex, Arc};

#[derive(Clone,Copy)]
pub struct ExampleJSONParser;
impl ExampleJSONParser {
    fn new() -> ExampleJSONParser {
        ExampleJSONParser{}
    }
}

impl ExampleJSONParser {
    fn parse(&self, info: &Vec<u8>)  -> Message {
        let vec_to_parse = info.clone();
        let message = String::from_utf8(vec_to_parse).unwrap();
        println!("Json parser for: {:?}", message);
        let msg: Message = match serde_json::from_str(&message)  {
            Err(..) =>   {println!("It was not parsed correctly"); Message::new_empty() },
            Ok(msg) => msg,
        };
        return msg
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Message {
    operation: String,
}

impl Message {
    fn new(operation: String) -> Message {
        Message {operation: operation}
    }
    fn new_empty() -> Message  {
        Message {operation: "".to_string()}
    }

}
pub trait Operation {
    fn run(self);
}

impl Operation for Message {
    fn run (self) {
        println!("hello!");
    }
}

pub struct MyBytesCodec {
    json_parser: ExampleJSONParser,
    //operations: HashMap<String, Arc<Mutex<dyn Operation + Send + 'static>>>,
    operations: HashMap<String, Box<dyn Operation + Send>>,
}

impl MyBytesCodec {
    fn new() -> MyBytesCodec {
        MyBytesCodec{json_parser: ExampleJSONParser::new(), operations: HashMap::new()}
    }
}

impl Decoder for MyBytesCodec {
    type Item = Message;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<Message>> {
        if buf.len() == 0 {
            return Ok(None);
        }
        let data = buf.clone().to_vec();
        let cloned_data = data.clone();
        let parsed = self.json_parser.parse(&cloned_data);
        buf.clear();
        Ok(Some(parsed))
    }
}

impl Encoder for MyBytesCodec {
    type Item = Message;
    type Error = io::Error;

    fn encode(&mut self, data: Message, buf: &mut BytesMut) -> io::Result<()> {
        buf.extend(serde_json::to_string(&data)?.into_bytes());
        Ok(())
    }
}

fn main() {
    let addr = "127.0.0.1:12345".parse().unwrap();
    let listener = TcpListener::bind(&addr).expect("unable to bind TCP listener");
    let server = listener.incoming()
            .map_err(|e| eprintln!("accept failed = {:?}", e))
            .for_each(move |socket| {
                let framed = MyBytesCodec::new().framed(socket);
                let (_writer, reader) = framed.split();

                /* function to handle connection  */
                let handle_conn = reader.for_each(|message| {
                    println!("my parsed message!!: {:?}", serde_json::to_string(&message));
                    Ok(())
                })
                .and_then(|()| {
                    println!("Socket received FIN packet and closed connection");
                    Ok(())
                })
                .or_else(|err| {
                    println!("Socked closed with error: {:?}", err);
                    Err(err)

                })
                .then(|result| {
                    println!("Socket closed with result: {:?}", result);
                    Ok(())
                });

            tokio::spawn(handle_conn)
    });
    tokio::run(server);
}

<|endoftext|>


<commit_before>// Copyright (c) 2016 Linus Färnstrand <faern@faern.net>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for sending and receiving data link layer packets on a fake network managed
//! by in memory FIFO queues. Useful for writing tests.

use std::io;
use std::sync::mpsc::{self, Receiver, Sender};
use std::thread;
use std::time;

use datalink::{self, EthernetDataLinkChannelIterator, EthernetDataLinkReceiver,
               EthernetDataLinkSender, NetworkInterface};
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};
use packet::Packet;
use util::MacAddr;

/// Configuration for the dummy datalink backend
#[derive(Debug)]
pub struct Config {
    /// The fake network will pull packets (or errors) form this `Receiver`
    pub in_packets_rx: Receiver<io::Result<Box<[u8]>>>,

    in_packets_tx: Option<Sender<io::Result<Box<[u8]>>>>,

    /// All packets sent to this fake network will end up on this `Sender`
    pub out_packets_tx: Sender<Vec<u8>>,

    out_packets_rx: Option<Receiver<Vec<u8>>>,
}

impl Config {
    /// Get the `Sender` handle that can inject packets in the fake network
    pub fn inject_handle(&mut self) -> Option<Sender<io::Result<Box<[u8]>>>> {
        self.in_packets_tx.take()
    }

    /// Get the `Receiver` handle where packets sent to the fake network can be read
    pub fn read_handle(&mut self) -> Option<Receiver<Vec<u8>>> {
        self.out_packets_rx.take()
    }
}

impl<'a> From<&'a datalink::Config> for Config {
    /// This conversion will not allow injecting and reading packets from the dummy network.
    /// To do that please create your own `dummy::Config`
    fn from(_config: &datalink::Config) -> Config {
        Config::default()
    }
}

impl Default for Config {
    /// This conversion will not allow injecting and reading packets from the dummy network.
    /// To do that please create your own `dummy::Config`
    fn default() -> Config {
        let (in_tx, in_rx) = mpsc::channel();
        let (out_tx, out_rx) = mpsc::channel();
        Config {
            in_packets_rx: in_rx,
            in_packets_tx: Some(in_tx),
            out_packets_tx: out_tx,
            out_packets_rx: Some(out_rx),
        }
    }
}

/// Create a data link channel backed by FIFO queues. Useful for debugging and testing.
pub fn channel(_: &NetworkInterface, config: Config) -> io::Result<datalink::Channel> {
    let sender = Box::new(MockEthernetDataLinkSender { out_packets: config.out_packets_tx });
    let receiver =
        Box::new(MockEthernetDataLinkReceiver { in_packets: Some(config.in_packets_rx) });

    Ok(datalink::Channel::Ethernet(sender, receiver))
}

struct MockEthernetDataLinkSender {
    out_packets: Sender<Vec<u8>>,
}

impl EthernetDataLinkSender for MockEthernetDataLinkSender {
    fn build_and_send(&mut self,
                      _num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(MutableEthernetPacket))
        -> Option<io::Result<()>> {
        let mut buffer = vec![0; packet_size];
        {
            let pkg = MutableEthernetPacket::new(&mut buffer[..]).unwrap();
            func(pkg);
        }
        // Send the data to the queue. Don't care if it's closed
        self.out_packets.send(buffer).unwrap_or(());
        Some(Ok(()))
    }

    fn send_to(&mut self,
               packet: &EthernetPacket,
               _dst: Option<NetworkInterface>)
        -> Option<io::Result<()>> {
        let buffer = packet.packet().to_vec();
        self.out_packets.send(buffer).unwrap_or(());
        Some(Ok(()))
    }
}

struct MockEthernetDataLinkReceiver {
    in_packets: Option<Receiver<io::Result<Box<[u8]>>>>,
}

impl EthernetDataLinkReceiver for MockEthernetDataLinkReceiver {
    fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
        Box::new(MockEthernetDataLinkChannelIterator {
            in_packets: self.in_packets.take().expect("Only one receiver allowed"),
            used_packets: vec![],
        })
    }
}

struct MockEthernetDataLinkChannelIterator {
    in_packets: Receiver<io::Result<Box<[u8]>>>,
    used_packets: Vec<Box<[u8]>>,
}

impl<'a> EthernetDataLinkChannelIterator<'a> for MockEthernetDataLinkChannelIterator {
    fn next(&mut self) -> io::Result<EthernetPacket> {
        match self.in_packets.recv() {
            Ok(result) => {
                // A network event happened. Might be a packet or a simulated error
                match result {
                    Ok(buffer) => {
                        self.used_packets.push(buffer);
                        let buffer_ref = &*self.used_packets[self.used_packets.len() - 1];
                        let packet = EthernetPacket::new(buffer_ref).unwrap();
                        Ok(packet)
                    }
                    Err(e) => Err(e),
                }
            }
            Err(_) => {
                // The channel supplying fake packets is broken. The user lost/destroyed their
                // inject_handle. This means there will never be any more packets sent to this
                // dummy network. To simulate an idle network we block and sleep forever here.
                loop {
                    thread::sleep(time::Duration::new(::std::u64::MAX, 0));
                }
            }
        }
    }
}

/// Get three fake interfaces generated with `dummy_interface`
pub fn interfaces() -> Vec<NetworkInterface> {
    (0..3).map(|i| dummy_interface(i)).collect()
}

/// Generates a fake `NetworkInterface`.
/// The name of the interface will be `ethX` where X is the integer `i`.
/// The index will be `i`.
/// The MAC will be `01:02:03:04:05:i`.
pub fn dummy_interface(i: u8) -> NetworkInterface {
    NetworkInterface {
        name: format!("eth{}", i),
        index: i as u32,
        mac: Some(MacAddr::new(1, 2, 3, 4, 5, i)),
        ips: None,
        flags: 0,
    }
}
<commit_msg>Add tests to datalink::dummy<commit_after>// Copyright (c) 2016 Linus Färnstrand <faern@faern.net>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for sending and receiving data link layer packets on a fake network managed
//! by in memory FIFO queues. Useful for writing tests.

use std::io;
use std::sync::mpsc::{self, Receiver, Sender};
use std::thread;
use std::time;

use datalink::{self, EthernetDataLinkChannelIterator, EthernetDataLinkReceiver,
               EthernetDataLinkSender, NetworkInterface};
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};
use packet::Packet;
use util::MacAddr;

/// Configuration for the dummy datalink backend. Contains `std::sync::mpsc`
/// channels that are used to communicate with the fake network.
#[derive(Debug)]
pub struct Config {
    /// The fake network will pull packets (or errors) form this `Receiver`
    pub in_packets_rx: Receiver<io::Result<Box<[u8]>>>,

    in_packets_tx: Option<Sender<io::Result<Box<[u8]>>>>,

    /// All packets sent to this fake network will end up on this `Sender`
    pub out_packets_tx: Sender<Box<[u8]>>,

    out_packets_rx: Option<Receiver<Box<[u8]>>>,
}

impl Config {
    /// Get the `Sender` handle that can inject packets in the fake network
    pub fn inject_handle(&mut self) -> Option<Sender<io::Result<Box<[u8]>>>> {
        self.in_packets_tx.take()
    }

    /// Get the `Receiver` handle where packets sent to the fake network can be read
    pub fn read_handle(&mut self) -> Option<Receiver<Box<[u8]>>> {
        self.out_packets_rx.take()
    }
}

impl<'a> From<&'a datalink::Config> for Config {
    /// This conversion will not allow injecting and reading packets from the dummy network.
    /// To do that please create your own `dummy::Config`
    fn from(_config: &datalink::Config) -> Config {
        Config::default()
    }
}

impl Default for Config {
    /// This conversion will not allow injecting and reading packets from the dummy network.
    /// To do that please create your own `dummy::Config`
    fn default() -> Config {
        let (in_tx, in_rx) = mpsc::channel();
        let (out_tx, out_rx) = mpsc::channel();
        Config {
            in_packets_rx: in_rx,
            in_packets_tx: Some(in_tx),
            out_packets_tx: out_tx,
            out_packets_rx: Some(out_rx),
        }
    }
}

/// Create a data link channel backed by FIFO queues. Useful for debugging and testing.
pub fn channel(_: &NetworkInterface, config: Config) -> io::Result<datalink::Channel> {
    let sender = Box::new(MockEthernetDataLinkSender { out_packets: config.out_packets_tx });
    let receiver =
        Box::new(MockEthernetDataLinkReceiver { in_packets: Some(config.in_packets_rx) });

    Ok(datalink::Channel::Ethernet(sender, receiver))
}

struct MockEthernetDataLinkSender {
    out_packets: Sender<Box<[u8]>>,
}

impl EthernetDataLinkSender for MockEthernetDataLinkSender {
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(MutableEthernetPacket))
        -> Option<io::Result<()>> {
        for _ in 0..num_packets {
            let mut buffer = vec![0; packet_size];
            {
                let pkg = match MutableEthernetPacket::new(&mut buffer[..]) {
                    Some(pkg) => pkg,
                    None => return None,
                };
                func(pkg);
            }
            // Send the data to the queue. Don't care if it's closed
            self.out_packets.send(buffer.into_boxed_slice()).unwrap_or(());
        }
        Some(Ok(()))
    }

    fn send_to(&mut self,
               packet: &EthernetPacket,
               _dst: Option<NetworkInterface>)
        -> Option<io::Result<()>> {
        let buffer = packet.packet().to_vec();
        self.out_packets.send(buffer.into_boxed_slice()).unwrap_or(());
        Some(Ok(()))
    }
}

struct MockEthernetDataLinkReceiver {
    in_packets: Option<Receiver<io::Result<Box<[u8]>>>>,
}

impl EthernetDataLinkReceiver for MockEthernetDataLinkReceiver {
    fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
        Box::new(MockEthernetDataLinkChannelIterator {
            in_packets: self.in_packets.take().expect("Only one receiver allowed"),
            used_packets: vec![],
        })
    }
}

struct MockEthernetDataLinkChannelIterator {
    in_packets: Receiver<io::Result<Box<[u8]>>>,
    used_packets: Vec<Box<[u8]>>,
}

impl<'a> EthernetDataLinkChannelIterator<'a> for MockEthernetDataLinkChannelIterator {
    fn next(&mut self) -> io::Result<EthernetPacket> {
        match self.in_packets.recv() {
            Ok(result) => {
                // A network event happened. Might be a packet or a simulated error
                match result {
                    Ok(buffer) => {
                        self.used_packets.push(buffer);
                        let buffer_ref = &*self.used_packets[self.used_packets.len() - 1];
                        let packet = EthernetPacket::new(buffer_ref).unwrap();
                        Ok(packet)
                    }
                    Err(e) => Err(e),
                }
            }
            Err(_) => {
                // The channel supplying fake packets is broken. The user lost/destroyed their
                // inject_handle. This means there will never be any more packets sent to this
                // dummy network. To simulate an idle network we block and sleep forever here.
                loop {
                    thread::sleep(time::Duration::new(::std::u64::MAX, 0));
                }
            }
        }
    }
}

/// Get three fake interfaces generated with `dummy_interface`.
pub fn interfaces() -> Vec<NetworkInterface> {
    (0..3).map(|i| dummy_interface(i)).collect()
}

/// Generates a fake `NetworkInterface`.
/// The name of the interface will be `ethX` where X is the integer `i`.
/// The index will be `i`.
/// The MAC will be `01:02:03:04:05:i`.
pub fn dummy_interface(i: u8) -> NetworkInterface {
    NetworkInterface {
        name: format!("eth{}", i),
        index: i as u32,
        mac: Some(MacAddr::new(1, 2, 3, 4, 5, i)),
        ips: None,
        flags: 0,
    }
}

#[cfg(test)]
mod tests {
    use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
    use std::io;
    use std::thread::{sleep, spawn};
    use std::time::Duration;

    use packet::{MutablePacket, Packet};
    use packet::ethernet::EthernetPacket;
    use datalink::{EthernetDataLinkReceiver, EthernetDataLinkSender};
    use datalink::Channel::Ethernet;

    #[test]
    fn send_too_small_packet_size() {
        let (_, read_handle, mut tx, _) = create_net();
        // Check that it fails to send with too small packet sizes
        assert!(tx.build_and_send(1, 0, &mut |_| {}).is_none());
    }

    #[test]
    fn send_nothing() {
        let (_, read_handle, mut tx, _) = create_net();
        // Check that sending zero packets yields zero packets
        tx.build_and_send(0,
                            20,
                            &mut |_| {
                                panic!("Should not be called");
                            })
            .unwrap()
            .unwrap();
        assert!(read_handle.try_recv().is_err());
    }

    #[test]
    fn send_one_packet() {
        let (_, read_handle, mut tx, _) = create_net();
        // Check that sending one packet yields one packet
        tx.build_and_send(1,
                            20,
                            &mut |mut pkg| {
                                assert_eq!(pkg.packet().len(), 20);
                                pkg.packet_mut()[0] = 9;
                                pkg.packet_mut()[19] = 201;
                            })
            .unwrap()
            .unwrap();
        let pkg = read_handle.try_recv().expect("Expected one packet to be sent");
        assert!(read_handle.try_recv().is_err());
        assert_eq!(pkg.len(), 20);
        assert_eq!(pkg[0], 9);
        assert_eq!(pkg[19], 201);
    }

    #[test]
    fn send_multiple_packets() {
        let (_, read_handle, mut tx, _) = create_net();
        // Check that sending multiple packets does the correct thing
        let mut closure_counter = 0;
        tx.build_and_send(3,
                            20,
                            &mut |mut pkg| {
                                pkg.packet_mut()[0] = closure_counter;
                                closure_counter += 1;
                            })
            .unwrap()
            .unwrap();
        for i in 0..3 {
            let pkg = read_handle.try_recv().expect("Expected a packet");
            assert_eq!(pkg[0], i);
        }
        assert!(read_handle.try_recv().is_err());
    }

    #[test]
    fn send_to() {
        let (_, read_handle, mut tx, _) = create_net();
        let mut buffer = vec![0; 20];
        buffer[1] = 34;
        buffer[18] = 76;
        let pkg = EthernetPacket::new(&buffer[..]).unwrap();

        tx.send_to(&pkg, None).unwrap().unwrap();
        let pkg = read_handle.try_recv().expect("Expected one packet to be sent");
        assert!(read_handle.try_recv().is_err());
        assert_eq!(pkg.len(), 20);
        assert_eq!(pkg[1], 34);
        assert_eq!(pkg[18], 76);
    }

    #[test]
    fn read_nothing() {
        let (inject_handle, _, _, mut rx) = create_net();
        let (control_tx, control_rx) = mpsc::channel();
        spawn(move || {
            let mut rx_iter = rx.iter();
            rx_iter.next().expect("Should not happen 1");
            control_tx.send(()).expect("Should not happen 2");
        });
        sleep(Duration::new(0, 1_000_000));
        match control_rx.try_recv() {
            Ok(_) => panic!("Nothing should have arrived"),
            Err(TryRecvError::Disconnected) => panic!("Thread should not have quit"),
            Err(TryRecvError::Empty) => (),
        }
    }

    #[test]
    fn read_one_pkg() {
        let (inject_handle, _, _, mut rx) = create_net();

        let buffer = vec![0; 20];
        inject_handle.send(Ok(buffer.into_boxed_slice())).unwrap();

        let mut rx_iter = rx.iter();
        let pkg = rx_iter.next().expect("Expected a packet");
        assert_eq!(pkg.packet().len(), 20);
    }

    #[test]
    fn read_multiple_pkgs() {
        let (inject_handle, _, _, mut rx) = create_net();

        for i in 0..3 {
            let buffer = vec![i; 20];
            inject_handle.send(Ok(buffer.into_boxed_slice())).unwrap();
        }

        let mut rx_iter = rx.iter();
        {
            let pkg1 = rx_iter.next().expect("Expected a packet");
            assert_eq!(pkg1.packet()[0], 0);
        }
        {
            let pkg2 = rx_iter.next().expect("Expected a packet");
            assert_eq!(pkg2.packet()[0], 1);
        }
        {
            let pkg3 = rx_iter.next().expect("Expected a packet");
            assert_eq!(pkg3.packet()[0], 2);
        }
    }

    fn create_net()
        -> (Sender<io::Result<Box<[u8]>>>,
            Receiver<Box<[u8]>>,
            Box<EthernetDataLinkSender>,
            Box<EthernetDataLinkReceiver>) {
        let interface = super::dummy_interface(56);
        let mut config = super::Config::default();
        let inject_handle = config.inject_handle().unwrap();
        let read_handle = config.read_handle().unwrap();

        let channel = super::channel(&interface, config);
        let (tx, rx) = match channel {
            Ok(Ethernet(tx, rx)) => (tx, rx),
            _ => panic!("Not a valid channel returned"),
        };
        (inject_handle, read_handle, tx, rx)
    }
}
<|endoftext|>


<commit_before>extern crate structopt;
#[macro_use]
extern crate structopt_derive;

use structopt::StructOpt;

fn part1(skip: usize) -> usize {
    let mut spinlock = vec![0];
    let mut current_pos = 1;
    for item in 1..2018 {
        current_pos = (current_pos + skip + 1) % spinlock.len();
        spinlock.insert(current_pos, item);
    }
    spinlock[(current_pos + 1) % spinlock.len()]
}

fn part2(skip: usize) -> usize {
    let mut len = 1;
    let mut current_pos = 1;
    let mut after_zero = 0;
    for item in 1..50_000_001 {
        current_pos = (current_pos + skip + 1) % len;
        len += 1; // as if we are inserting
        if current_pos == 0 {
            after_zero = item
        }
    }
    after_zero
}

fn main() {
    let opt = Opt::from_args();
    println!(
        "Part 1: {}",
        part1(opt.input.parse().expect("Could not read input"))
    );
    println!(
        "Part 2: {}",
        part2(opt.input.parse().expect("Could not read input"))
    );
}

#[derive(StructOpt, Debug)]
#[structopt(name = "day13", about = "Advent of code 2017 day 13")]
struct Opt {
    #[structopt(help = "Input")] input: String,
}

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

    #[test]
    fn part1_test() {
        assert_eq!(part1(3), 638);
    }
}
<commit_msg>Optimize 2017 day 17<commit_after>extern crate structopt;
#[macro_use]
extern crate structopt_derive;

use structopt::StructOpt;

fn part1(skip: usize) -> usize {
    let mut spinlock = vec![0];
    let mut current_pos = 1;
    for item in 1..2018 {
        current_pos = (current_pos + skip + 1) % spinlock.len();
        spinlock.insert(current_pos, item);
    }
    spinlock[(current_pos + 1) % spinlock.len()]
}

fn part2(skip: usize) -> usize {
    let mut len = 1;
    let mut current_pos = 1;
    let mut after_zero = 0;
    let mut item = 0;
    while item <= 50_000_000 {
        current_pos = (current_pos + skip + 1) % len;
        if current_pos == 0 {
            after_zero = item
        }
        len += 1; // as if we are inserting
        item += 1;
        let remaining = len - 1 - current_pos;
        let ignore = if remaining % (skip + 1) == 0 {
            (remaining / (skip + 1)).max(1) - 1
        } else {
            remaining / (skip + 1)
        };
        item += ignore;
        len += ignore;
        current_pos += ignore * (skip + 1);
    }
    after_zero
}

fn main() {
    let opt = Opt::from_args();
    println!(
        "Part 1: {}",
        part1(opt.input.parse().expect("Could not read input"))
    );
    println!(
        "Part 2: {}",
        part2(opt.input.parse().expect("Could not read input"))
    );
}

#[derive(StructOpt, Debug)]
#[structopt(name = "day13", about = "Advent of code 2017 day 13")]
struct Opt {
    #[structopt(help = "Input")] input: String,
}

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

    #[test]
    fn part1_test() {
        assert_eq!(part1(3), 638);
    }
}
<|endoftext|>