<commit_before>//! Platform-specific extensions to `std` for WASI.
//!
//! Provides access to platform-level information on WASI, and exposes
//! WASI-specific functions that would otherwise be inappropriate as
//! part of the core `std` library.
//!
//! It exposes more ways to deal with platform-specific strings (`OsStr`,
//! `OsString`), allows to set permissions more granularly, extract low-level
//! file descriptors from files and sockets, and has platform-specific helpers
//! for spawning processes.
//!
//! # Examples
//!
//! ```no_run
//! use std::fs::File;
//! use std::os::wasi::prelude::*;
//!
//! fn main() -> std::io::Result<()> {
//!     let f = File::create("foo.txt")?;
//!     let fd = f.as_raw_fd();
//!
//!     // use fd with native WASI bindings
//!
//!     Ok(())
//! }
//! ```

#![stable(feature = "rust1", since = "1.0.0")]
#![deny(unsafe_op_in_unsafe_fn)]
#![doc(cfg(target_os = "wasi"))]

pub mod ffi;
pub mod fs;
pub mod io;

/// A prelude for conveniently writing platform-specific code.
///
/// Includes all extension traits, and some important type definitions.
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
    #[doc(no_inline)]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::ffi::{OsStrExt, OsStringExt};
    #[doc(no_inline)]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::FileTypeExt;
    #[doc(no_inline)]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt};
    #[doc(no_inline)]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
}
<commit_msg>Expand WASI abbreviation in docs<commit_after>//! Platform-specific extensions to `std` for the WebAssembly System Interface (WASI).
//!
//! Provides access to platform-level information on WASI, and exposes
//! WASI-specific functions that would otherwise be inappropriate as
//! part of the core `std` library.
//!
//! It exposes more ways to deal with platform-specific strings (`OsStr`,
//! `OsString`), allows to set permissions more granularly, extract low-level
//! file descriptors from files and sockets, and has platform-specific helpers
//! for spawning processes.
//!
//! # Examples
//!
//! ```no_run
//! use std::fs::File;
//! use std::os::wasi::prelude::*;
//!
//! fn main() -> std::io::Result<()> {
//!     let f = File::create("foo.txt")?;
//!     let fd = f.as_raw_fd();
//!
//!     // use fd with native WASI bindings
//!
//!     Ok(())
//! }
//! ```

#![stable(feature = "rust1", since = "1.0.0")]
#![deny(unsafe_op_in_unsafe_fn)]
#![doc(cfg(target_os = "wasi"))]

pub mod ffi;
pub mod fs;
pub mod io;

/// A prelude for conveniently writing platform-specific code.
///
/// Includes all extension traits, and some important type definitions.
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
    #[doc(no_inline)]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::ffi::{OsStrExt, OsStringExt};
    #[doc(no_inline)]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::FileTypeExt;
    #[doc(no_inline)]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt};
    #[doc(no_inline)]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::fmt;

use http::mime::{Mime, TopLevel, SubLevel};
use http::hyper::{header, FreshHyperResponse, StatusCode};
use outcome::{self, IntoOutcome};
use outcome::Outcome::*;
use response::Stream;

/// Type alias for the `Outcome` of a `Responder`.
pub type Outcome<'a> = outcome::Outcome<(), (), (StatusCode, FreshHyperResponse<'a>)>;

impl<'a, T, E> IntoOutcome<(), (), (StatusCode, FreshHyperResponse<'a>)> for Result<T, E> {
    fn into_outcome(self) -> Outcome<'a> {
        match self {
            Ok(_) => Success(()),
            Err(_) => Failure(())
        }
    }
}

/// Trait implemented by types that send a response to clients.
///
/// Types that implement this trait can be used as the return type of a handler,
/// as illustrated below:
///
/// ```rust,ignore
/// #[get("/")]
/// fn index() -> T { ... }
/// ```
///
/// In this example, `T` can be any type that implements `Responder`.
///
/// # Outcomes
///
/// The returned [Outcome](/rocket/outcome/index.html) of a `respond` call
/// determines how the response will be processed, if at all.
///
/// * **Success**
///
///   An `Outcome` of `Success` indicates that the responder was successful in
///   sending the response to the client. No further processing will occur as a
///   result.
///
/// * **Failure**
///
///   An `Outcome` of `Failure` indicates that the responder failed after
///   beginning a response. The response is incomplete, and there is no way to
///   salvage the response. No further processing will occur.
///
/// * **Forward**(StatusCode, FreshHyperResponse<'a>)
///
///   If the `Outcome` is `Forward`, the response will be forwarded to the
///   designated error [Catcher](/rocket/struct.Catcher.html) for the given
///   `StatusCode`. This requires that a response wasn't started and thus is
///   still fresh.
///
/// # Provided Implementations
///
/// Rocket implements `Responder` for several standard library types. Their
/// behavior is documented here. Note that the `Result` implementation is
/// overloaded, allowing for two `Responder`s to be used at once, depending on
/// the variant.
///
///   * **impl<'a> Responder for &'a str**
///
///     Sets the `Content-Type`t to `text/plain` if it is not already set. Sends
///     the string as the body of the response.
///
///   * **impl Responder for String**
///
///     Sets the `Content-Type`t to `text/html` if it is not already set. Sends
///     the string as the body of the response.
///
///   * **impl Responder for File**
///
///     Streams the `File` to the client. This is essentially an alias to
///     Stream<File>.
///
///   * **impl Responder for ()**
///
///     Responds with an empty body.
///
///   * **impl<T: Responder> Responder for Option<T>**
///
///     If the `Option` is `Some`, the wrapped responder is used to respond to
///     respond to the client. Otherwise, the response is forwarded to the 404
///     error catcher and a warning is printed to the console.
///
///   * **impl<T: Responder, E: Debug> Responder for Result<T, E>**
///
///     If the `Result` is `Ok`, the wrapped responder is used to respond to the
///     client. Otherwise, the response is forwarded to the 500 error catcher
///     and the error is printed to the console using the `Debug`
///     implementation.
///
///   * **impl<T: Responder, E: Responder + Debug> Responder for Result<T, E>**
///
///     If the `Result` is `Ok`, the wrapped `Ok` responder is used to respond
///     to the client. If the `Result` is `Err`, the wrapped error responder is
///     used to respond to the client.
///
/// # Implementation Tips
///
/// This section describes a few best practices to take into account when
/// implementing `Responder`.
///
/// ## Debug
///
/// A type implementing `Responder` should implement the `Debug` trait when
/// possible. This is because the `Responder` implementation for `Result`
/// requires its `Err` type to implement `Debug`. Therefore, a type implementing
/// `Debug` can more easily be composed.
///
/// ## Check Before Changing
///
/// Unless a given type is explicitly designed to change some information in
/// ther esponse, it should first _check_ that some information hasn't been set
/// before _changing_ that information. For example, before setting the
/// `Content-Type` header of a response, first check that the header hasn't been
/// set.
pub trait Responder {
    /// Attempts to write a response to `res`.
    ///
    /// If writing the response successfully completes, an outcome of `Success`
    /// is returned. If writing the response begins but fails, an outcome of
    /// `Failure` is returned. If writing a response fails before writing
    /// anything out, an outcome of `Forward` can be returned, which causes the
    /// response to be written by the appropriate error catcher instead.
    fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a>;
}

/// Sets the `Content-Type`t to `text/plain` if it is not already set. Sends the
/// string as the body of the response.
impl<'a> Responder for &'a str {
    fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
        if res.headers().get::<header::ContentType>().is_none() {
            let mime = Mime(TopLevel::Text, SubLevel::Plain, vec![]);
            res.headers_mut().set(header::ContentType(mime));
        }

        res.send(self.as_bytes()).into_outcome()
    }
}

impl Responder for String {
    fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a> {
        if res.headers().get::<header::ContentType>().is_none() {
            let mime = Mime(TopLevel::Text, SubLevel::Html, vec![]);
            res.headers_mut().set(header::ContentType(mime));
        }

        res.send(self.as_bytes()).into_outcome()
    }
}

/// Essentially aliases Stream<File>.
impl Responder for File {
    fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
        Stream::from(self).respond(res)
    }
}

/// Empty response.
impl Responder for () {
    fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
        res.send(&[]).into_outcome()
    }
}

impl<T: Responder> Responder for Option<T> {
    fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
        if let Some(ref mut val) = *self {
            val.respond(res)
        } else {
            warn_!("Response was `None`.");
            Forward((StatusCode::NotFound, res))
        }
    }
}

impl<T: Responder, E: fmt::Debug> Responder for Result<T, E> {
    // prepend with `default` when using impl specialization
    default fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
        match *self {
            Ok(ref mut val) => val.respond(res),
            Err(ref e) => {
                error_!("{:?}", e);
                Forward((StatusCode::InternalServerError, res))
            }
        }
    }
}

impl<T: Responder, E: Responder + fmt::Debug> Responder for Result<T, E> {
    fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
        match *self {
            Ok(ref mut responder) => responder.respond(res),
            Err(ref mut responder) => responder.respond(res),
        }
    }
}
<commit_msg>Add example implementation for Responder.<commit_after>use std::fs::File;
use std::fmt;

use http::mime::{Mime, TopLevel, SubLevel};
use http::hyper::{header, FreshHyperResponse, StatusCode};
use outcome::{self, IntoOutcome};
use outcome::Outcome::*;
use response::Stream;

/// Type alias for the `Outcome` of a `Responder`.
pub type Outcome<'a> = outcome::Outcome<(), (), (StatusCode, FreshHyperResponse<'a>)>;

impl<'a, T, E> IntoOutcome<(), (), (StatusCode, FreshHyperResponse<'a>)> for Result<T, E> {
    fn into_outcome(self) -> Outcome<'a> {
        match self {
            Ok(_) => Success(()),
            Err(_) => Failure(())
        }
    }
}

/// Trait implemented by types that send a response to clients.
///
/// Types that implement this trait can be used as the return type of a handler,
/// as illustrated below:
///
/// ```rust,ignore
/// #[get("/")]
/// fn index() -> T { ... }
/// ```
///
/// In this example, `T` can be any type that implements `Responder`.
///
/// # Outcomes
///
/// The returned [Outcome](/rocket/outcome/index.html) of a `respond` call
/// determines how the response will be processed, if at all.
///
/// * **Success**
///
///   An `Outcome` of `Success` indicates that the responder was successful in
///   sending the response to the client. No further processing will occur as a
///   result.
///
/// * **Failure**
///
///   An `Outcome` of `Failure` indicates that the responder failed after
///   beginning a response. The response is incomplete, and there is no way to
///   salvage the response. No further processing will occur.
///
/// * **Forward**(StatusCode, FreshHyperResponse<'a>)
///
///   If the `Outcome` is `Forward`, the response will be forwarded to the
///   designated error [Catcher](/rocket/struct.Catcher.html) for the given
///   `StatusCode`. This requires that a response wasn't started and thus is
///   still fresh.
///
/// # Provided Implementations
///
/// Rocket implements `Responder` for several standard library types. Their
/// behavior is documented here. Note that the `Result` implementation is
/// overloaded, allowing for two `Responder`s to be used at once, depending on
/// the variant.
///
///   * **impl<'a> Responder for &'a str**
///
///     Sets the `Content-Type`t to `text/plain` if it is not already set. Sends
///     the string as the body of the response.
///
///   * **impl Responder for String**
///
///     Sets the `Content-Type`t to `text/html` if it is not already set. Sends
///     the string as the body of the response.
///
///   * **impl Responder for File**
///
///     Streams the `File` to the client. This is essentially an alias to
///     Stream<File>.
///
///   * **impl Responder for ()**
///
///     Responds with an empty body.
///
///   * **impl<T: Responder> Responder for Option<T>**
///
///     If the `Option` is `Some`, the wrapped responder is used to respond to
///     respond to the client. Otherwise, the response is forwarded to the 404
///     error catcher and a warning is printed to the console.
///
///   * **impl<T: Responder, E: Debug> Responder for Result<T, E>**
///
///     If the `Result` is `Ok`, the wrapped responder is used to respond to the
///     client. Otherwise, the response is forwarded to the 500 error catcher
///     and the error is printed to the console using the `Debug`
///     implementation.
///
///   * **impl<T: Responder, E: Responder + Debug> Responder for Result<T, E>**
///
///     If the `Result` is `Ok`, the wrapped `Ok` responder is used to respond
///     to the client. If the `Result` is `Err`, the wrapped error responder is
///     used to respond to the client.
///
/// # Implementation Tips
///
/// This section describes a few best practices to take into account when
/// implementing `Responder`.
///
/// ## Debug
///
/// A type implementing `Responder` should implement the `Debug` trait when
/// possible. This is because the `Responder` implementation for `Result`
/// requires its `Err` type to implement `Debug`. Therefore, a type implementing
/// `Debug` can more easily be composed.
///
/// ## Check Before Changing
///
/// Unless a given type is explicitly designed to change some information in
/// ther esponse, it should first _check_ that some information hasn't been set
/// before _changing_ that information. For example, before setting the
/// `Content-Type` header of a response, first check that the header hasn't been
/// set.
///
/// # Example
///
/// Say that you have a custom type, `Person`:
///
/// ```rust
/// struct Person {
///     name: String,
///     age: u16
/// }
/// ```
///
/// You'd like to use `Person` as a `Responder` so that you can return a
/// `Person` directly from a handler:
///
/// ```rust,ignore
/// #[get("/person/<id>")]
/// fn person(id: usize) -> Option<Person> {
///     Person::from_id(id)
/// }
/// ```
///
/// You want the `Person` responder to set two header fields: `X-Person-Name`
/// and `X-Person-Age` as well as supply a custom representation of the object
/// (`Content-Type: application/x-person`) in the body of the response. The
/// following `Responder` implementation accomplishes this:
///
/// ```rust
/// # #[derive(Debug)]
/// # struct Person { name: String, age: u16 }
/// #
/// use std::str::FromStr;
/// use std::fmt::Write;
///
/// use rocket::response::{Responder, Outcome};
/// use rocket::outcome::IntoOutcome;
/// use rocket::http::hyper::{FreshHyperResponse, header};
/// use rocket::http::ContentType;
///
/// impl Responder for Person {
///     fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
///         // Set the custom headers.
///         let name_bytes = self.name.clone().into_bytes();
///         let age_bytes = self.age.to_string().into_bytes();
///         res.headers_mut().set_raw("X-Person-Name", vec![name_bytes]);
///         res.headers_mut().set_raw("X-Person-Age", vec![age_bytes]);
///
///         // Set the custom Content-Type header.
///         let ct = ContentType::from_str("application/x-person").unwrap();
///         res.headers_mut().set(header::ContentType(ct.into()));
///
///         // Write out the "custom" body, here just the debug representation.
///         let mut repr = String::with_capacity(50);
///         write!(&mut repr, "{:?}", *self);
///         res.send(repr.as_bytes()).into_outcome()
///     }
/// }
/// ```
pub trait Responder {
    /// Attempts to write a response to `res`.
    ///
    /// If writing the response successfully completes, an outcome of `Success`
    /// is returned. If writing the response begins but fails, an outcome of
    /// `Failure` is returned. If writing a response fails before writing
    /// anything out, an outcome of `Forward` can be returned, which causes the
    /// response to be written by the appropriate error catcher instead.
    fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a>;
}

/// Sets the `Content-Type`t to `text/plain` if it is not already set. Sends the
/// string as the body of the response.
impl<'a> Responder for &'a str {
    fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
        if res.headers().get::<header::ContentType>().is_none() {
            let mime = Mime(TopLevel::Text, SubLevel::Plain, vec![]);
            res.headers_mut().set(header::ContentType(mime));
        }

        res.send(self.as_bytes()).into_outcome()
    }
}

impl Responder for String {
    fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a> {
        if res.headers().get::<header::ContentType>().is_none() {
            let mime = Mime(TopLevel::Text, SubLevel::Html, vec![]);
            res.headers_mut().set(header::ContentType(mime));
        }

        res.send(self.as_bytes()).into_outcome()
    }
}

/// Essentially aliases Stream<File>.
impl Responder for File {
    fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
        Stream::from(self).respond(res)
    }
}

/// Empty response.
impl Responder for () {
    fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
        res.send(&[]).into_outcome()
    }
}

impl<T: Responder> Responder for Option<T> {
    fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
        if let Some(ref mut val) = *self {
            val.respond(res)
        } else {
            warn_!("Response was `None`.");
            Forward((StatusCode::NotFound, res))
        }
    }
}

impl<T: Responder, E: fmt::Debug> Responder for Result<T, E> {
    // prepend with `default` when using impl specialization
    default fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
        match *self {
            Ok(ref mut val) => val.respond(res),
            Err(ref e) => {
                error_!("{:?}", e);
                Forward((StatusCode::InternalServerError, res))
            }
        }
    }
}

impl<T: Responder, E: Responder + fmt::Debug> Responder for Result<T, E> {
    fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
        match *self {
            Ok(ref mut responder) => responder.respond(res),
            Err(ref mut responder) => responder.respond(res),
        }
    }
}
<|endoftext|>


<commit_before>use ra_syntax::{
    ast::{self, AstNode},
    TextSize, T,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: remove_dbg
//
// Removes `dbg!()` macro call.
//
// ```
// fn main() {
//     <|>dbg!(92);
// }
// ```
// ->
// ```
// fn main() {
//     92;
// }
// ```
pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;

    if !is_valid_macrocall(&macro_call, "dbg")? {
        return None;
    }

    let macro_range = macro_call.syntax().text_range();

    let macro_content = {
        let macro_args = macro_call.token_tree()?.syntax().clone();

        let text = macro_args.text();
        let without_parens = TextSize::of('(')..text.len() - TextSize::of(')');
        text.slice(without_parens).to_string()
    };

    let target = macro_call.syntax().text_range();
    acc.add(AssistId("remove_dbg", AssistKind::Refactor), "Remove dbg!()", target, |builder| {
        builder.replace(macro_range, macro_content);
    })
}

/// Verifies that the given macro_call actually matches the given name
/// and contains proper ending tokens
fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<bool> {
    let path = macro_call.path()?;
    let name_ref = path.segment()?.name_ref()?;

    // Make sure it is actually a dbg-macro call, dbg followed by !
    let excl = path.syntax().next_sibling_or_token()?;

    if name_ref.text() != macro_name || excl.kind() != T![!] {
        return None;
    }

    let node = macro_call.token_tree()?.syntax().clone();
    let first_child = node.first_child_or_token()?;
    let last_child = node.last_child_or_token()?;

    match (first_child.kind(), last_child.kind()) {
        (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => Some(true),
        _ => Some(false),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    #[test]
    fn test_remove_dbg() {
        check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1");

        check_assist(remove_dbg, "dbg!<|>((1 + 1))", "(1 + 1)");

        check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 + 1");

        check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = 1 + 1");

        check_assist(
            remove_dbg,
            "
fn foo(n: usize) {
    if let Some(_) = dbg!(n.<|>checked_sub(4)) {
        // ...
    }
}
",
            "
fn foo(n: usize) {
    if let Some(_) = n.checked_sub(4) {
        // ...
    }
}
",
        );
    }
    #[test]
    fn test_remove_dbg_with_brackets_and_braces() {
        check_assist(remove_dbg, "dbg![<|>1 + 1]", "1 + 1");
        check_assist(remove_dbg, "dbg!{<|>1 + 1}", "1 + 1");
    }

    #[test]
    fn test_remove_dbg_not_applicable() {
        check_assist_not_applicable(remove_dbg, "<|>vec![1, 2, 3]");
        check_assist_not_applicable(remove_dbg, "<|>dbg(5, 6, 7)");
        check_assist_not_applicable(remove_dbg, "<|>dbg!(5, 6, 7");
    }

    #[test]
    fn remove_dbg_target() {
        check_assist_target(
            remove_dbg,
            "
fn foo(n: usize) {
    if let Some(_) = dbg!(n.<|>checked_sub(4)) {
        // ...
    }
}
",
            "dbg!(n.checked_sub(4))",
        );
    }

    #[test]
    fn remove_dbg_leave_semicolon() {
        // https://github.com/rust-analyzer/rust-analyzer/issues/5129#issuecomment-651399779
        // not quite though
        let code = "
let res = <|>dbg!(1 * 20); // needless comment
";
        let expected = "
let res = 1 * 20; // needless comment
";
        check_assist(remove_dbg, code, expected);
    }

    #[test]
    fn remove_dbg_keep_expression() {
        let code = "
let res = <|>dbg!(a + b).foo();";
        let expected = "let res = (a + b).foo();";
        check_assist(remove_dbg, code, expected);
    }
}
<commit_msg>Make all test fn names consistent in remove_dbg<commit_after>use ra_syntax::{
    ast::{self, AstNode},
    TextSize, T,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: remove_dbg
//
// Removes `dbg!()` macro call.
//
// ```
// fn main() {
//     <|>dbg!(92);
// }
// ```
// ->
// ```
// fn main() {
//     92;
// }
// ```
pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;

    if !is_valid_macrocall(&macro_call, "dbg")? {
        return None;
    }

    let macro_range = macro_call.syntax().text_range();

    let macro_content = {
        let macro_args = macro_call.token_tree()?.syntax().clone();

        let text = macro_args.text();
        let without_parens = TextSize::of('(')..text.len() - TextSize::of(')');
        text.slice(without_parens).to_string()
    };

    let target = macro_call.syntax().text_range();
    acc.add(AssistId("remove_dbg", AssistKind::Refactor), "Remove dbg!()", target, |builder| {
        builder.replace(macro_range, macro_content);
    })
}

/// Verifies that the given macro_call actually matches the given name
/// and contains proper ending tokens
fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<bool> {
    let path = macro_call.path()?;
    let name_ref = path.segment()?.name_ref()?;

    // Make sure it is actually a dbg-macro call, dbg followed by !
    let excl = path.syntax().next_sibling_or_token()?;

    if name_ref.text() != macro_name || excl.kind() != T![!] {
        return None;
    }

    let node = macro_call.token_tree()?.syntax().clone();
    let first_child = node.first_child_or_token()?;
    let last_child = node.last_child_or_token()?;

    match (first_child.kind(), last_child.kind()) {
        (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => Some(true),
        _ => Some(false),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    #[test]
    fn test_remove_dbg() {
        check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1");

        check_assist(remove_dbg, "dbg!<|>((1 + 1))", "(1 + 1)");

        check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 + 1");

        check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = 1 + 1");

        check_assist(
            remove_dbg,
            "
fn foo(n: usize) {
    if let Some(_) = dbg!(n.<|>checked_sub(4)) {
        // ...
    }
}
",
            "
fn foo(n: usize) {
    if let Some(_) = n.checked_sub(4) {
        // ...
    }
}
",
        );
    }

    #[test]
    fn test_remove_dbg_with_brackets_and_braces() {
        check_assist(remove_dbg, "dbg![<|>1 + 1]", "1 + 1");
        check_assist(remove_dbg, "dbg!{<|>1 + 1}", "1 + 1");
    }

    #[test]
    fn test_remove_dbg_not_applicable() {
        check_assist_not_applicable(remove_dbg, "<|>vec![1, 2, 3]");
        check_assist_not_applicable(remove_dbg, "<|>dbg(5, 6, 7)");
        check_assist_not_applicable(remove_dbg, "<|>dbg!(5, 6, 7");
    }

    #[test]
    fn test_remove_dbg_target() {
        check_assist_target(
            remove_dbg,
            "
fn foo(n: usize) {
    if let Some(_) = dbg!(n.<|>checked_sub(4)) {
        // ...
    }
}
",
            "dbg!(n.checked_sub(4))",
        );
    }

    #[test]
    fn test_remove_dbg_keep_semicolon() {
        // https://github.com/rust-analyzer/rust-analyzer/issues/5129#issuecomment-651399779
        // not quite though
        let code = "
let res = <|>dbg!(1 * 20); // needless comment
";
        let expected = "
let res = 1 * 20; // needless comment
";
        check_assist(remove_dbg, code, expected);
    }

    #[test]
    fn test_remove_dbg_keep_expression() {
        let code = "
let res = <|>dbg!(a + b).foo();";
        let expected = "let res = (a + b).foo();";
        check_assist(remove_dbg, code, expected);
    }

    #[test]
    fn test_remove_dbg_from_inside_fn() {
        let code = "
fn square(x: u32) -> u32 {
    x * x
}

fn main() {
    let x = square(dbg<|>!(5 + 10));
    println!(\"{}\", x);
}";

        let expected = "
fn square(x: u32) -> u32 {
    x * x
}

fn main() {
    let x = square(5 + 10);
    println!(\"{}\", x);
}";
        check_assist_target(remove_dbg, code, "dbg!(5 + 10)");
        check_assist(remove_dbg, code, expected);
    }
}
<|endoftext|>


<commit_before>pub trait Summarizable {
    fn summary(&self) -> String {
        String::from("Read more...")
    }
}

pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}

impl Summarizable for NewsArticle {
    fn summary(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Summarizable for Tweet {
    fn summary(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Change default implementation so it uses other method defined in trait<commit_after>pub trait Summarizable {
    fn author_summary(&self) -> String;

    fn summary(&self) -> String {
        String::from("Read more from {}...", self.author_summary())
    }
}

pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}

impl Summarizable for NewsArticle {
    fn summary(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Summarizable for Tweet {
    fn summary(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>use state_processing::{per_block_processing, per_block_processing_without_verifying_block_signature, per_slot_processing};
use serde_derive::Deserialize;
use serde_yaml;
use std::{fs::File, io::prelude::*, path::PathBuf};
use types::*;
#[allow(unused_imports)]
use yaml_utils;

#[derive(Debug, Deserialize)]
pub struct TestCase {
    pub name: String,
    pub config: ChainSpec,
    pub verify_signatures: bool,
    pub initial_state: BeaconState,
    pub blocks: Vec<BeaconBlock>,
}

#[derive(Debug, Deserialize)]
pub struct TestDoc {
    pub title: String,
    pub summary: String,
    pub fork: String,
    pub test_cases: Vec<TestCase>,
}

#[test]
fn test_read_yaml() {
    // Test sanity-check_small-config_32-vals.yaml
    let mut file = {
        let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        file_path_buf.push("yaml_utils/specs/sanity-check_small-config_32-vals.yaml");

        File::open(file_path_buf).unwrap()
    };

    let mut yaml_str = String::new();

    file.read_to_string(&mut yaml_str).unwrap();

    yaml_str = yaml_str.to_lowercase();

    let _doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap();

    // Test sanity-check_default-config_100-vals.yaml
    file = {
        let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        file_path_buf.push("yaml_utils/specs/sanity-check_default-config_100-vals.yaml");

        File::open(file_path_buf).unwrap()
    };

    yaml_str = String::new();

    file.read_to_string(&mut yaml_str).unwrap();

    yaml_str = yaml_str.to_lowercase();

    let _doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap();
}

#[test]
fn run_state_transition_tests_small() {
    // Test sanity-check_small-config_32-vals.yaml
    let mut file = {
        let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        file_path_buf.push("yaml_utils/specs/sanity-check_small-config_32-vals.yaml");

        File::open(file_path_buf).unwrap()
    };
    let mut yaml_str = String::new();
    file.read_to_string(&mut yaml_str).unwrap();
    yaml_str = yaml_str.to_lowercase();

    let doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap();

    // Run Tests
    for (i, test_case) in doc.test_cases.iter().enumerate() {
        let mut state = test_case.initial_state.clone();
        for block in test_case.blocks.iter() {
            while block.slot > state.slot {
                let latest_block_header = state.latest_block_header.clone();
                let res = per_slot_processing(&mut state, &latest_block_header, &test_case.config).unwrap();
            }
            if test_case.verify_signatures {
                let res = per_block_processing(&mut state, &block, &test_case.config);
                if  res.is_err() {
                    println!("{:?}", i);
                    println!("{:?}", res);
                };
            } else {
                let res = per_block_processing_without_verifying_block_signature(&mut state, &block, &test_case.config);
                if  res.is_err() {
                    println!("{:?}", i);
                    println!("{:?}", res);
                }
            }
        }
    }
}
<commit_msg>Run rustfmt<commit_after>use serde_derive::Deserialize;
use serde_yaml;
use state_processing::{
    per_block_processing, per_block_processing_without_verifying_block_signature,
    per_slot_processing,
};
use std::{fs::File, io::prelude::*, path::PathBuf};
use types::*;
#[allow(unused_imports)]
use yaml_utils;

#[derive(Debug, Deserialize)]
pub struct TestCase {
    pub name: String,
    pub config: ChainSpec,
    pub verify_signatures: bool,
    pub initial_state: BeaconState,
    pub blocks: Vec<BeaconBlock>,
}

#[derive(Debug, Deserialize)]
pub struct TestDoc {
    pub title: String,
    pub summary: String,
    pub fork: String,
    pub test_cases: Vec<TestCase>,
}

#[test]
fn test_read_yaml() {
    // Test sanity-check_small-config_32-vals.yaml
    let mut file = {
        let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        file_path_buf.push("yaml_utils/specs/sanity-check_small-config_32-vals.yaml");

        File::open(file_path_buf).unwrap()
    };

    let mut yaml_str = String::new();

    file.read_to_string(&mut yaml_str).unwrap();

    yaml_str = yaml_str.to_lowercase();

    let _doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap();

    // Test sanity-check_default-config_100-vals.yaml
    file = {
        let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        file_path_buf.push("yaml_utils/specs/sanity-check_default-config_100-vals.yaml");

        File::open(file_path_buf).unwrap()
    };

    yaml_str = String::new();

    file.read_to_string(&mut yaml_str).unwrap();

    yaml_str = yaml_str.to_lowercase();

    let _doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap();
}

#[test]
fn run_state_transition_tests_small() {
    // Test sanity-check_small-config_32-vals.yaml
    let mut file = {
        let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        file_path_buf.push("yaml_utils/specs/sanity-check_small-config_32-vals.yaml");

        File::open(file_path_buf).unwrap()
    };
    let mut yaml_str = String::new();
    file.read_to_string(&mut yaml_str).unwrap();
    yaml_str = yaml_str.to_lowercase();

    let doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap();

    // Run Tests
    for (i, test_case) in doc.test_cases.iter().enumerate() {
        let mut state = test_case.initial_state.clone();
        for block in test_case.blocks.iter() {
            while block.slot > state.slot {
                let latest_block_header = state.latest_block_header.clone();
                let res = per_slot_processing(&mut state, &latest_block_header, &test_case.config)
                    .unwrap();
            }
            if test_case.verify_signatures {
                let res = per_block_processing(&mut state, &block, &test_case.config);
                if res.is_err() {
                    println!("{:?}", i);
                    println!("{:?}", res);
                };
            } else {
                let res = per_block_processing_without_verifying_block_signature(
                    &mut state,
                    &block,
                    &test_case.config,
                );
                if res.is_err() {
                    println!("{:?}", i);
                    println!("{:?}", res);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! DICOM association module
//!
//! This module contains utilities for establishing associations
//! between DICOM nodes via TCP/IP.
//!
//! As an association requester, often as a service class user (SCU),
//! a new association can be started
//! via the [`ClientAssociationOptions`][1] type.
//! The minimum required properties are the accepted abstract syntaxes
//! and the TCP socket address to the target node.
//!
//! As an association acceptor,
//! usually taking the role of a service class provider (SCP),
//! a newly created [TCP stream][2] can be passed to
//! a previously prepared [`ServerAssociationOptions`][3].
//!
//! [1]: crate::association::client::ClientAssociationOptions
//! [2]: std::net::TcpStream
//! [3]: crate::association::server::ServerAssociationOptions
pub mod client;
pub mod server;

pub(crate) mod pdata;

pub use client::{ClientAssociation, ClientAssociationOptions};
pub use pdata::PDataWriter;
pub use server::{ServerAssociation, ServerAssociationOptions};

/// A service class user or a provider.
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
pub enum ServiceClassRole {
    /// Service Class User
    Scu,
    /// Service Class Provider
    Scp,
}
<commit_msg>[ul] remove association::ServiceClassRole<commit_after>//! DICOM association module
//!
//! This module contains utilities for establishing associations
//! between DICOM nodes via TCP/IP.
//!
//! As an association requester, often as a service class user (SCU),
//! a new association can be started
//! via the [`ClientAssociationOptions`][1] type.
//! The minimum required properties are the accepted abstract syntaxes
//! and the TCP socket address to the target node.
//!
//! As an association acceptor,
//! usually taking the role of a service class provider (SCP),
//! a newly created [TCP stream][2] can be passed to
//! a previously prepared [`ServerAssociationOptions`][3].
//!
//! [1]: crate::association::client::ClientAssociationOptions
//! [2]: std::net::TcpStream
//! [3]: crate::association::server::ServerAssociationOptions
pub mod client;
pub mod server;

pub(crate) mod pdata;

pub use client::{ClientAssociation, ClientAssociationOptions};
pub use pdata::PDataWriter;
pub use server::{ServerAssociation, ServerAssociationOptions};
<|endoftext|>


<commit_before>//! Connection pooling via r2d2.
//!
//! Note: This module requires enabling the `r2d2` feature

extern crate r2d2;

pub use self::r2d2::*;

/// A re-export of [`r2d2::Error`], which is only used by methods on [`r2d2::Pool`].
///
/// [`r2d2::Error`]: ../../r2d2/struct.Error.html
/// [`r2d2::Pool`]: ../../r2d2/struct.Pool.html
pub type PoolError = self::r2d2::Error;

use std::convert::Into;
use std::fmt;
use std::marker::PhantomData;

use backend::UsesAnsiSavepointSyntax;
use connection::{AnsiTransactionManager, SimpleConnection};
use deserialize::{Queryable, QueryableByName};
use prelude::*;
use query_builder::{AsQuery, QueryFragment, QueryId};
use sql_types::HasSqlType;

/// An r2d2 connection manager for use with Diesel.
///
/// See the [r2d2 documentation] for usage examples.
///
/// [r2d2 documentation]: ../../r2d2
#[derive(Debug, Clone)]
pub struct ConnectionManager<T> {
    database_url: String,
    _marker: PhantomData<T>,
}

unsafe impl<T: Send + 'static> Sync for ConnectionManager<T> {}

impl<T> ConnectionManager<T> {
    /// Returns a new connection manager,
    /// which establishes connections to the given database URL.
    pub fn new<S: Into<String>>(database_url: S) -> Self {
        ConnectionManager {
            database_url: database_url.into(),
            _marker: PhantomData,
        }
    }
}

/// The error used when managing connections with `r2d2`.
#[derive(Debug)]
pub enum Error {
    /// An error occurred establishing the connection
    ConnectionError(ConnectionError),

    /// An error occurred pinging the database
    QueryError(::result::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::ConnectionError(ref e) => e.fmt(f),
            Error::QueryError(ref e) => e.fmt(f),
        }
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ConnectionError(ref e) => e.description(),
            Error::QueryError(ref e) => e.description(),
        }
    }
}

impl<T> ManageConnection for ConnectionManager<T>
where
    T: Connection + Send + 'static,
{
    type Connection = T;
    type Error = Error;

    fn connect(&self) -> Result<T, Error> {
        T::establish(&self.database_url).map_err(Error::ConnectionError)
    }

    fn is_valid(&self, conn: &mut T) -> Result<(), Error> {
        conn.execute("SELECT 1")
            .map(|_| ())
            .map_err(Error::QueryError)
    }

    fn has_broken(&self, _conn: &mut T) -> bool {
        false
    }
}

impl<M> SimpleConnection for PooledConnection<M>
where
    M: ManageConnection,
    M::Connection: Connection + Send + 'static,
{
    fn batch_execute(&self, query: &str) -> QueryResult<()> {
        (&**self).batch_execute(query)
    }
}

impl<M> Connection for PooledConnection<M>
where
    M: ManageConnection,
    M::Connection: Connection<TransactionManager = AnsiTransactionManager> + Send + 'static,
    <M::Connection as Connection>::Backend: UsesAnsiSavepointSyntax,
{
    type Backend = <M::Connection as Connection>::Backend;
    type TransactionManager = <M::Connection as Connection>::TransactionManager;

    fn establish(_: &str) -> ConnectionResult<Self> {
        Err(ConnectionError::BadConnection(String::from(
            "Cannot directly establish a pooled connection",
        )))
    }

    fn execute(&self, query: &str) -> QueryResult<usize> {
        (&**self).execute(query)
    }

    fn query_by_index<T, U>(&self, source: T) -> QueryResult<Vec<U>>
    where
        T: AsQuery,
        T::Query: QueryFragment<Self::Backend> + QueryId,
        Self::Backend: HasSqlType<T::SqlType>,
        U: Queryable<T::SqlType, Self::Backend>,
    {
        (&**self).query_by_index(source)
    }

    fn query_by_name<T, U>(&self, source: &T) -> QueryResult<Vec<U>>
    where
        T: QueryFragment<Self::Backend> + QueryId,
        U: QueryableByName<Self::Backend>,
    {
        (&**self).query_by_name(source)
    }

    fn execute_returning_count<T>(&self, source: &T) -> QueryResult<usize>
    where
        T: QueryFragment<Self::Backend> + QueryId,
    {
        (&**self).execute_returning_count(source)
    }

    fn transaction_manager(&self) -> &Self::TransactionManager {
        (&**self).transaction_manager()
    }
}

#[cfg(test)]
mod tests {
    use std::sync::mpsc;
    use std::sync::Arc;
    use std::thread;

    use r2d2::*;
    use test_helpers::*;

    #[test]
    fn establish_basic_connection() {
        let manager = ConnectionManager::<TestConnection>::new(database_url());
        let pool = Arc::new(Pool::builder().max_size(2).build(manager).unwrap());

        let (s1, r1) = mpsc::channel();
        let (s2, r2) = mpsc::channel();

        let pool1 = Arc::clone(&pool);
        let t1 = thread::spawn(move || {
            let conn = pool1.get().unwrap();
            s1.send(()).unwrap();
            r2.recv().unwrap();
            drop(conn);
        });

        let pool2 = Arc::clone(&pool);
        let t2 = thread::spawn(move || {
            let conn = pool2.get().unwrap();
            s2.send(()).unwrap();
            r1.recv().unwrap();
            drop(conn);
        });

        t1.join().unwrap();
        t2.join().unwrap();

        pool.get().unwrap();
    }

    #[test]
    fn is_valid() {
        let manager = ConnectionManager::<TestConnection>::new(database_url());
        let pool = Pool::builder()
            .max_size(1)
            .test_on_check_out(true)
            .build(manager)
            .unwrap();

        pool.get().unwrap();
    }

    #[test]
    fn pooled_connection_impls_connection() {
        use select;
        use sql_types::Text;

        let manager = ConnectionManager::<TestConnection>::new(database_url());
        let pool = Pool::builder()
            .max_size(1)
            .test_on_check_out(true)
            .build(manager)
            .unwrap();
        let conn = pool.get().unwrap();

        let query = select("foo".into_sql::<Text>());
        assert_eq!("foo", query.get_result::<String>(&conn).unwrap());
    }
}
<commit_msg>Allow to customize r2d2 `is_valid` checks per backends<commit_after>//! Connection pooling via r2d2.
//!
//! Note: This module requires enabling the `r2d2` feature

extern crate r2d2;

pub use self::r2d2::*;

/// A re-export of [`r2d2::Error`], which is only used by methods on [`r2d2::Pool`].
///
/// [`r2d2::Error`]: ../../r2d2/struct.Error.html
/// [`r2d2::Pool`]: ../../r2d2/struct.Pool.html
pub type PoolError = self::r2d2::Error;

use std::convert::Into;
use std::fmt;
use std::marker::PhantomData;

use backend::UsesAnsiSavepointSyntax;
use connection::{AnsiTransactionManager, SimpleConnection};
use deserialize::{Queryable, QueryableByName};
use prelude::*;
use query_builder::{AsQuery, QueryFragment, QueryId};
use sql_types::HasSqlType;

/// An r2d2 connection manager for use with Diesel.
///
/// See the [r2d2 documentation] for usage examples.
///
/// [r2d2 documentation]: ../../r2d2
#[derive(Debug, Clone)]
pub struct ConnectionManager<T> {
    database_url: String,
    _marker: PhantomData<T>,
}

unsafe impl<T: Send + 'static> Sync for ConnectionManager<T> {}

impl<T> ConnectionManager<T> {
    /// Returns a new connection manager,
    /// which establishes connections to the given database URL.
    pub fn new<S: Into<String>>(database_url: S) -> Self {
        ConnectionManager {
            database_url: database_url.into(),
            _marker: PhantomData,
        }
    }
}

/// The error used when managing connections with `r2d2`.
#[derive(Debug)]
pub enum Error {
    /// An error occurred establishing the connection
    ConnectionError(ConnectionError),

    /// An error occurred pinging the database
    QueryError(::result::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::ConnectionError(ref e) => e.fmt(f),
            Error::QueryError(ref e) => e.fmt(f),
        }
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ConnectionError(ref e) => e.description(),
            Error::QueryError(ref e) => e.description(),
        }
    }
}

/// A trait indicating a connection could be used inside a r2d2 pool
pub trait R2D2Connection: Connection {
    /// Check if a connection is still valid
    fn ping(&self) -> QueryResult<()>;
}

#[cfg(feature = "postgres")]
impl R2D2Connection for ::pg::PgConnection {
    fn ping(&self) -> QueryResult<()> {
        self.execute("SELECT 1").map(|_| ())
    }
}

#[cfg(feature = "mysql")]
impl R2D2Connection for ::mysql::MysqlConnection {
    fn ping(&self) -> QueryResult<()> {
        self.execute("SELECT 1").map(|_| ())
    }
}

#[cfg(feature = "sqlite")]
impl R2D2Connection for ::sqlite::SqliteConnection {
    fn ping(&self) -> QueryResult<()> {
        self.execute("SELECT 1").map(|_| ())
    }
}

impl<T> ManageConnection for ConnectionManager<T>
where
    T: R2D2Connection + Send + 'static,
{
    type Connection = T;
    type Error = Error;

    fn connect(&self) -> Result<T, Error> {
        T::establish(&self.database_url).map_err(Error::ConnectionError)
    }

    fn is_valid(&self, conn: &mut T) -> Result<(), Error> {
        conn.ping().map_err(Error::QueryError)
    }

    fn has_broken(&self, _conn: &mut T) -> bool {
        false
    }
}

impl<M> SimpleConnection for PooledConnection<M>
where
    M: ManageConnection,
    M::Connection: R2D2Connection + Send + 'static,
{
    fn batch_execute(&self, query: &str) -> QueryResult<()> {
        (&**self).batch_execute(query)
    }
}

impl<M> Connection for PooledConnection<M>
where
    M: ManageConnection,
    M::Connection:
        Connection<TransactionManager = AnsiTransactionManager> + R2D2Connection + Send + 'static,
    <M::Connection as Connection>::Backend: UsesAnsiSavepointSyntax,
{
    type Backend = <M::Connection as Connection>::Backend;
    type TransactionManager = <M::Connection as Connection>::TransactionManager;

    fn establish(_: &str) -> ConnectionResult<Self> {
        Err(ConnectionError::BadConnection(String::from(
            "Cannot directly establish a pooled connection",
        )))
    }

    fn execute(&self, query: &str) -> QueryResult<usize> {
        (&**self).execute(query)
    }

    fn query_by_index<T, U>(&self, source: T) -> QueryResult<Vec<U>>
    where
        T: AsQuery,
        T::Query: QueryFragment<Self::Backend> + QueryId,
        Self::Backend: HasSqlType<T::SqlType>,
        U: Queryable<T::SqlType, Self::Backend>,
    {
        (&**self).query_by_index(source)
    }

    fn query_by_name<T, U>(&self, source: &T) -> QueryResult<Vec<U>>
    where
        T: QueryFragment<Self::Backend> + QueryId,
        U: QueryableByName<Self::Backend>,
    {
        (&**self).query_by_name(source)
    }

    fn execute_returning_count<T>(&self, source: &T) -> QueryResult<usize>
    where
        T: QueryFragment<Self::Backend> + QueryId,
    {
        (&**self).execute_returning_count(source)
    }

    fn transaction_manager(&self) -> &Self::TransactionManager {
        (&**self).transaction_manager()
    }
}

#[cfg(test)]
mod tests {
    use std::sync::mpsc;
    use std::sync::Arc;
    use std::thread;

    use r2d2::*;
    use test_helpers::*;

    #[test]
    fn establish_basic_connection() {
        let manager = ConnectionManager::<TestConnection>::new(database_url());
        let pool = Arc::new(Pool::builder().max_size(2).build(manager).unwrap());

        let (s1, r1) = mpsc::channel();
        let (s2, r2) = mpsc::channel();

        let pool1 = Arc::clone(&pool);
        let t1 = thread::spawn(move || {
            let conn = pool1.get().unwrap();
            s1.send(()).unwrap();
            r2.recv().unwrap();
            drop(conn);
        });

        let pool2 = Arc::clone(&pool);
        let t2 = thread::spawn(move || {
            let conn = pool2.get().unwrap();
            s2.send(()).unwrap();
            r1.recv().unwrap();
            drop(conn);
        });

        t1.join().unwrap();
        t2.join().unwrap();

        pool.get().unwrap();
    }

    #[test]
    fn is_valid() {
        let manager = ConnectionManager::<TestConnection>::new(database_url());
        let pool = Pool::builder()
            .max_size(1)
            .test_on_check_out(true)
            .build(manager)
            .unwrap();

        pool.get().unwrap();
    }

    #[test]
    fn pooled_connection_impls_connection() {
        use select;
        use sql_types::Text;

        let manager = ConnectionManager::<TestConnection>::new(database_url());
        let pool = Pool::builder()
            .max_size(1)
            .test_on_check_out(true)
            .build(manager)
            .unwrap();
        let conn = pool.get().unwrap();

        let query = select("foo".into_sql::<Text>());
        assert_eq!("foo", query.get_result::<String>(&conn).unwrap());
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{self, Write};

use crate::cannon::{self, CompilationFlags};
use crate::compiler::dora_entry_stub;
use crate::language::sem_analysis::{FctDefinition, FctDefinitionId};
use crate::language::ty::SourceTypeArray;
use crate::vm::SemAnalysis;

pub fn build(sa: &SemAnalysis, main_fct_id: FctDefinitionId) {
    let fct = sa.fcts.idx(main_fct_id);
    let fct = fct.read();

    write(sa, &*fct).expect("write failed");
}

fn write(sa: &SemAnalysis, fct: &FctDefinition) -> io::Result<()> {
    let mut file = File::create("program.s")?;
    writeln!(&mut file, ".text")?;

    writeln!(&mut file, "\t.globl _dora_main")?;
    writeln!(&mut file, "\t.p2align 4")?;
    writeln!(&mut file, "_dora_main:")?;
    let code_descriptor = cannon::compile(
        sa,
        &*fct,
        &SourceTypeArray::empty(),
        CompilationFlags::aot(),
    );
    write_binary_buffer(&mut file, &code_descriptor.code)?;

    writeln!(&mut file, "\t.globl _dora_entry_stub")?;
    writeln!(&mut file, "\t.p2align 4")?;
    writeln!(&mut file, "_dora_entry_stub:")?;
    let code_descriptor = dora_entry_stub::generate(sa);
    write_binary_buffer(&mut file, &code_descriptor.code)?;

    Ok(())
}

fn write_binary_buffer(file: &mut File, buffer: &[u8]) -> io::Result<()> {
    write!(file, ".byte {:x}", buffer.first().expect("empty buffer"))?;

    for &value in buffer.iter().skip(1) {
        write!(file, ", 0x{:x}", value)?;
    }

    writeln!(file)?;

    Ok(())
}
<commit_msg>aot: add function for emitting functions<commit_after>use std::fs::File;
use std::io::{self, Write};

use crate::cannon::{self, CompilationFlags};
use crate::compiler::dora_entry_stub;
use crate::language::sem_analysis::{FctDefinition, FctDefinitionId};
use crate::language::ty::SourceTypeArray;
use crate::masm::CodeDescriptor;
use crate::vm::SemAnalysis;

pub fn build(sa: &SemAnalysis, main_fct_id: FctDefinitionId) {
    let fct = sa.fcts.idx(main_fct_id);
    let fct = fct.read();

    write(sa, &*fct).expect("write failed");
}

fn write(sa: &SemAnalysis, fct: &FctDefinition) -> io::Result<()> {
    let mut file = File::create("program.s")?;
    writeln!(&mut file, ".text")?;

    let code_descriptor = cannon::compile(
        sa,
        &*fct,
        &SourceTypeArray::empty(),
        CompilationFlags::aot(),
    );
    write_fct(&mut file, "_dora_main", code_descriptor)?;

    let code_descriptor = dora_entry_stub::generate(sa);
    write_fct(&mut file, "_dora_entry_stub", code_descriptor)?;

    Ok(())
}

fn write_fct(file: &mut File, name: &str, code_descriptor: CodeDescriptor) -> io::Result<()> {
    writeln!(file, "\t.globl {}", name)?;
    writeln!(file, "\t.p2align 4")?;
    writeln!(file, "{}:", name)?;
    writeln!(file, "\t.cfi_startproc")?;
    write_binary_buffer(file, &code_descriptor.code)?;
    writeln!(file, "\t.cfi_endproc")?;

    Ok(())
}

fn write_binary_buffer(file: &mut File, buffer: &[u8]) -> io::Result<()> {
    write!(file, "\t.byte {:x}", buffer.first().expect("empty buffer"))?;

    for &value in buffer.iter().skip(1) {
        write!(file, ", 0x{:x}", value)?;
    }

    writeln!(file)?;

    Ok(())
}
<|endoftext|>


<commit_before>//! REPL for the gluon programming language
#![doc(html_root_url = "https://docs.rs/gluon_repl/0.13.1")] // # GLUON

#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate gluon_vm;
#[macro_use]
extern crate gluon_codegen;

use std::{
    ffi::OsStr,
    fs,
    io::{self, Write},
    path::{Path, PathBuf},
    sync::Arc,
};

use codespan_reporting::term::termcolor;
use quick_error::quick_error;
use structopt::StructOpt;
use walkdir::WalkDir;

use gluon::{base, parser, vm};

use crate::base::{
    filename_to_module,
    source::{self, Source},
};

use gluon::{
    new_vm_async, vm::thread::ThreadInternal, vm::Error as VMError, Result, Thread, ThreadExt,
};

mod repl;

quick_error! {
/// Error type wrapping all possible errors that can be generated from gluon
#[derive(Debug)]
#[allow(deprecated)]
enum Error {
    Failure(err: anyhow::Error) {
        display("{}", err)
        from()
    }
    Gluon(err: gluon::Error) {
        display("{}", err)
        from()
    }
}
}

const APP_INFO: app_dirs::AppInfo = app_dirs::AppInfo {
    name: "gluon-repl",
    author: "gluon-lang",
};

#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, VmType, Getable, Pushable)]
pub enum Color {
    Auto,
    Always,
    AlwaysAnsi,
    Never,
}

impl Into<termcolor::ColorChoice> for Color {
    fn into(self) -> termcolor::ColorChoice {
        use termcolor::ColorChoice::*;
        match self {
            Color::Auto => Auto,
            Color::Always => Always,
            Color::AlwaysAnsi => AlwaysAnsi,
            Color::Never => Never,
        }
    }
}

impl Default for Color {
    fn default() -> Color {
        Color::Auto
    }
}

impl ::std::str::FromStr for Color {
    type Err = &'static str;
    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        use crate::Color::*;
        Ok(match s {
            "auto" => Auto,
            "always" => Always,
            "always-ansi" => AlwaysAnsi,
            "never" => Never,
            _ => return Err("Expected one of 'auto', 'always', 'always-ansi', 'never'"),
        })
    }
}

#[derive(StructOpt)]
#[structopt(about = "Formats gluon source code")]
pub struct FmtOpt {
    #[structopt(name = "FILE", parse(from_os_str), help = "Formats each file")]
    input: Vec<PathBuf>,
}

#[derive(StructOpt)]
pub enum SubOpt {
    #[structopt(name = "fmt", about = "Formats gluon source code")]
    Fmt(FmtOpt),
    #[structopt(name = "doc", about = "Documents gluon source code")]
    Doc(::gluon_doc::Opt),
}

const LONG_VERSION: &str = concat!(clap::crate_version!(), "\n", "commit: ", env!("GIT_HASH"));

#[derive(StructOpt)]
#[structopt(about = "executes gluon programs", long_version = LONG_VERSION)]
pub struct Opt {
    #[structopt(short = "i", long = "interactive", help = "Starts the repl")]
    interactive: bool,

    #[structopt(
        long = "color",
        default_value = "auto",
        help = "Coloring: auto, always, always-ansi, never"
    )]
    color: Color,

    #[structopt(
        long = "prompt",
        short = "p",
        default_value = "> ",
        help = "String printed as the prompt for the repl"
    )]
    prompt: String,

    #[structopt(
        long = "debug",
        default_value = "none",
        help = "Debug Level: none, low, high"
    )]
    debug_level: base::DebugLevel,

    #[structopt(
        long = "no-std",
        help = "Skip searching the internal standard library for requested modules."
    )]
    no_std: bool,

    #[structopt(name = "FILE", help = "Executes each file as a gluon program")]
    input: Vec<String>,

    #[structopt(subcommand)]
    subcommand_opt: Option<SubOpt>,
}

async fn run_files<I>(vm: &Thread, files: I) -> Result<()>
where
    I: IntoIterator,
    I::Item: AsRef<str>,
{
    for file in files {
        vm.load_file_async(file.as_ref()).await?;
    }
    Ok(())
}

#[cfg(feature = "env_logger")]
fn init_env_logger() {
    let _ = ::env_logger::try_init();
}

#[cfg(not(feature = "env_logger"))]
fn init_env_logger() {}

async fn format(file: &str, file_map: Arc<source::FileMap>, opt: &Opt) -> Result<String> {
    let thread = new_vm_async().await;
    thread.get_database_mut().use_standard_lib(!opt.no_std);

    Ok(thread
        .format_expr_async(
            &mut gluon_format::Formatter::default(),
            file,
            file_map.src(),
        )
        .await?)
}

async fn fmt_file(name: &Path, opt: &Opt) -> Result<()> {
    use std::fs::File;
    use std::io::Read;

    let mut buffer = String::new();
    {
        let mut input_file = File::open(name)?;
        input_file.read_to_string(&mut buffer)?;
    }

    let module_name = filename_to_module(&name.display().to_string());
    let mut code_map = source::CodeMap::new();
    let file_map = code_map.add_filemap(module_name.clone().into(), buffer);
    let formatted = format(&module_name, file_map.clone(), opt).await?;

    // Avoid touching the .glu file if it did not change
    if file_map.src() != formatted {
        let bk_name = name.with_extension("glu.bk");
        let tmp_name = name.with_extension("tmp");
        {
            let mut backup = File::create(&*bk_name)?;
            backup.write_all(formatted.as_bytes())?;
        }
        fs::rename(name, tmp_name)?;
        fs::rename(bk_name, name)?;
    }
    Ok(())
}

async fn fmt_stdio(opt: &Opt) -> Result<()> {
    use std::io::{stdin, stdout, Read};

    let mut buffer = String::new();
    stdin().read_to_string(&mut buffer)?;

    let mut code_map = source::CodeMap::new();
    let file_map = code_map.add_filemap("STDIN".into(), buffer);

    let formatted = format("STDIN", file_map, opt).await?;
    stdout().write_all(formatted.as_bytes())?;
    Ok(())
}

async fn run(opt: &Opt, color: Color, vm: &Thread) -> std::result::Result<(), Error> {
    vm.global_env().set_debug_level(opt.debug_level.clone());
    match opt.subcommand_opt {
        Some(SubOpt::Fmt(ref fmt_opt)) => {
            if !fmt_opt.input.is_empty() {
                let mut gluon_files = fmt_opt
                    .input
                    .iter()
                    .flat_map(|arg| {
                        WalkDir::new(arg).into_iter().filter_map(|entry| {
                            entry.ok().and_then(|entry| {
                                if entry.file_type().is_file()
                                    && entry.path().extension() == Some(OsStr::new("glu"))
                                {
                                    Some(entry.path().to_owned())
                                } else {
                                    None
                                }
                            })
                        })
                    })
                    .collect::<Vec<_>>();
                gluon_files.sort();
                gluon_files.dedup();

                for file in gluon_files {
                    fmt_file(&file, opt).await?;
                }
            } else {
                fmt_stdio(opt).await?;
            }
        }
        Some(SubOpt::Doc(ref doc_opt)) => {
            let input = &doc_opt.input;
            let output = &doc_opt.output;
            let thread = new_vm_async().await;
            gluon_doc::generate_for_path(&thread, input, output)?;
        }
        None => {
            if opt.interactive {
                let prompt = opt.prompt.clone();
                let debug_level = opt.debug_level.clone();
                let use_std_lib = !opt.no_std;
                repl::run(color, &prompt, debug_level, use_std_lib).await?;
            } else if !opt.input.is_empty() {
                run_files(&vm, &opt.input).await?;
            } else {
                writeln!(io::stderr(), "{}", Opt::clap().get_matches().usage())
                    .expect("Error writing help to stderr");
            }
        }
    }
    Ok(())
}

#[tokio::main(basic_scheduler)]
async fn main() {
    init_env_logger();

    let opt = Opt::from_args();

    let vm = new_vm_async().await;
    vm.get_database_mut()
        .use_standard_lib(!opt.no_std)
        .run_io(true);

    let color = opt.color;
    let result = run(&opt, opt.color, &vm).await;
    if let Err(err) = result {
        match err {
            Error::Gluon(gluon::Error::VM(VMError::Message(_))) => {
                eprintln!("{}\n{}", err, vm.context().stacktrace(0))
            }
            Error::Gluon(err) => {
                let mut stderr = termcolor::StandardStream::stderr(color.into());
                if let Err(err) = err.emit(&mut stderr) {
                    eprintln!("{}", err);
                } else {
                    eprintln!("");
                }
            }
            Error::Failure(err) => {
                eprintln!("{}", err);
            }
        }
        ::std::process::exit(1);
    }
}

#[cfg(test)]
mod tests {
    // If nothing else this suppresses the unused imports warnings when compiling in test mode
    #[test]
    fn execute_repl_help() {
        super::main();
    }
}
<commit_msg>Allow -- in repl arguments<commit_after>//! REPL for the gluon programming language
#![doc(html_root_url = "https://docs.rs/gluon_repl/0.13.1")] // # GLUON

#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate gluon_vm;
#[macro_use]
extern crate gluon_codegen;

use std::{
    ffi::OsStr,
    fs,
    io::{self, Write},
    path::{Path, PathBuf},
    sync::Arc,
};

use codespan_reporting::term::termcolor;
use quick_error::quick_error;
use structopt::StructOpt;
use walkdir::WalkDir;

use gluon::{base, parser, vm};

use crate::base::{
    filename_to_module,
    source::{self, Source},
};

use gluon::{
    new_vm_async, vm::thread::ThreadInternal, vm::Error as VMError, Result, Thread, ThreadExt,
};

mod repl;

quick_error! {
/// Error type wrapping all possible errors that can be generated from gluon
#[derive(Debug)]
#[allow(deprecated)]
enum Error {
    Failure(err: anyhow::Error) {
        display("{}", err)
        from()
    }
    Gluon(err: gluon::Error) {
        display("{}", err)
        from()
    }
}
}

const APP_INFO: app_dirs::AppInfo = app_dirs::AppInfo {
    name: "gluon-repl",
    author: "gluon-lang",
};

#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, VmType, Getable, Pushable)]
pub enum Color {
    Auto,
    Always,
    AlwaysAnsi,
    Never,
}

impl Into<termcolor::ColorChoice> for Color {
    fn into(self) -> termcolor::ColorChoice {
        use termcolor::ColorChoice::*;
        match self {
            Color::Auto => Auto,
            Color::Always => Always,
            Color::AlwaysAnsi => AlwaysAnsi,
            Color::Never => Never,
        }
    }
}

impl Default for Color {
    fn default() -> Color {
        Color::Auto
    }
}

impl ::std::str::FromStr for Color {
    type Err = &'static str;
    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        use crate::Color::*;
        Ok(match s {
            "auto" => Auto,
            "always" => Always,
            "always-ansi" => AlwaysAnsi,
            "never" => Never,
            _ => return Err("Expected one of 'auto', 'always', 'always-ansi', 'never'"),
        })
    }
}

#[derive(StructOpt)]
#[structopt(about = "Formats gluon source code")]
pub struct FmtOpt {
    #[structopt(name = "FILE", parse(from_os_str), help = "Formats each file")]
    input: Vec<PathBuf>,
}

#[derive(StructOpt)]
pub enum SubOpt {
    #[structopt(name = "fmt", about = "Formats gluon source code")]
    Fmt(FmtOpt),
    #[structopt(name = "doc", about = "Documents gluon source code")]
    Doc(::gluon_doc::Opt),
}

const LONG_VERSION: &str = concat!(clap::crate_version!(), "\n", "commit: ", env!("GIT_HASH"));

#[derive(StructOpt)]
#[structopt(about = "executes gluon programs", long_version = LONG_VERSION)]
pub struct Opt {
    #[structopt(short = "i", long = "interactive", help = "Starts the repl")]
    interactive: bool,

    #[structopt(
        long = "color",
        default_value = "auto",
        help = "Coloring: auto, always, always-ansi, never"
    )]
    color: Color,

    #[structopt(
        long = "prompt",
        short = "p",
        default_value = "> ",
        help = "String printed as the prompt for the repl"
    )]
    prompt: String,

    #[structopt(
        long = "debug",
        default_value = "none",
        help = "Debug Level: none, low, high"
    )]
    debug_level: base::DebugLevel,

    #[structopt(
        long = "no-std",
        help = "Skip searching the internal standard library for requested modules."
    )]
    no_std: bool,

    #[structopt(name = "FILE", help = "Executes each file as a gluon program")]
    input: Vec<String>,

    #[structopt(
        last = true,
        name = "ARGS",
        help = "Extra arguments passed to the gluon program"
    )]
    #[allow(dead_code)]
    args: Vec<String>,

    #[structopt(subcommand)]
    subcommand_opt: Option<SubOpt>,
}

async fn run_files<I>(vm: &Thread, files: I) -> Result<()>
where
    I: IntoIterator,
    I::Item: AsRef<str>,
{
    for file in files {
        vm.load_file_async(file.as_ref()).await?;
    }
    Ok(())
}

#[cfg(feature = "env_logger")]
fn init_env_logger() {
    let _ = ::env_logger::try_init();
}

#[cfg(not(feature = "env_logger"))]
fn init_env_logger() {}

async fn format(file: &str, file_map: Arc<source::FileMap>, opt: &Opt) -> Result<String> {
    let thread = new_vm_async().await;
    thread.get_database_mut().use_standard_lib(!opt.no_std);

    Ok(thread
        .format_expr_async(
            &mut gluon_format::Formatter::default(),
            file,
            file_map.src(),
        )
        .await?)
}

async fn fmt_file(name: &Path, opt: &Opt) -> Result<()> {
    use std::fs::File;
    use std::io::Read;

    let mut buffer = String::new();
    {
        let mut input_file = File::open(name)?;
        input_file.read_to_string(&mut buffer)?;
    }

    let module_name = filename_to_module(&name.display().to_string());
    let mut code_map = source::CodeMap::new();
    let file_map = code_map.add_filemap(module_name.clone().into(), buffer);
    let formatted = format(&module_name, file_map.clone(), opt).await?;

    // Avoid touching the .glu file if it did not change
    if file_map.src() != formatted {
        let bk_name = name.with_extension("glu.bk");
        let tmp_name = name.with_extension("tmp");
        {
            let mut backup = File::create(&*bk_name)?;
            backup.write_all(formatted.as_bytes())?;
        }
        fs::rename(name, tmp_name)?;
        fs::rename(bk_name, name)?;
    }
    Ok(())
}

async fn fmt_stdio(opt: &Opt) -> Result<()> {
    use std::io::{stdin, stdout, Read};

    let mut buffer = String::new();
    stdin().read_to_string(&mut buffer)?;

    let mut code_map = source::CodeMap::new();
    let file_map = code_map.add_filemap("STDIN".into(), buffer);

    let formatted = format("STDIN", file_map, opt).await?;
    stdout().write_all(formatted.as_bytes())?;
    Ok(())
}

async fn run(opt: &Opt, color: Color, vm: &Thread) -> std::result::Result<(), Error> {
    vm.global_env().set_debug_level(opt.debug_level.clone());
    match opt.subcommand_opt {
        Some(SubOpt::Fmt(ref fmt_opt)) => {
            if !fmt_opt.input.is_empty() {
                let mut gluon_files = fmt_opt
                    .input
                    .iter()
                    .flat_map(|arg| {
                        WalkDir::new(arg).into_iter().filter_map(|entry| {
                            entry.ok().and_then(|entry| {
                                if entry.file_type().is_file()
                                    && entry.path().extension() == Some(OsStr::new("glu"))
                                {
                                    Some(entry.path().to_owned())
                                } else {
                                    None
                                }
                            })
                        })
                    })
                    .collect::<Vec<_>>();
                gluon_files.sort();
                gluon_files.dedup();

                for file in gluon_files {
                    fmt_file(&file, opt).await?;
                }
            } else {
                fmt_stdio(opt).await?;
            }
        }
        Some(SubOpt::Doc(ref doc_opt)) => {
            let input = &doc_opt.input;
            let output = &doc_opt.output;
            let thread = new_vm_async().await;
            gluon_doc::generate_for_path(&thread, input, output)?;
        }
        None => {
            if opt.interactive {
                let prompt = opt.prompt.clone();
                let debug_level = opt.debug_level.clone();
                let use_std_lib = !opt.no_std;
                repl::run(color, &prompt, debug_level, use_std_lib).await?;
            } else if !opt.input.is_empty() {
                run_files(&vm, &opt.input).await?;
            } else {
                writeln!(io::stderr(), "{}", Opt::clap().get_matches().usage())
                    .expect("Error writing help to stderr");
            }
        }
    }
    Ok(())
}

#[tokio::main(basic_scheduler)]
async fn main() {
    init_env_logger();

    let opt = Opt::from_args();

    let vm = new_vm_async().await;
    vm.get_database_mut()
        .use_standard_lib(!opt.no_std)
        .run_io(true);

    let color = opt.color;
    let result = run(&opt, opt.color, &vm).await;
    if let Err(err) = result {
        match err {
            Error::Gluon(gluon::Error::VM(VMError::Message(_))) => {
                eprintln!("{}\n{}", err, vm.context().stacktrace(0))
            }
            Error::Gluon(err) => {
                let mut stderr = termcolor::StandardStream::stderr(color.into());
                if let Err(err) = err.emit(&mut stderr) {
                    eprintln!("{}", err);
                } else {
                    eprintln!("");
                }
            }
            Error::Failure(err) => {
                eprintln!("{}", err);
            }
        }
        ::std::process::exit(1);
    }
}

#[cfg(test)]
mod tests {
    // If nothing else this suppresses the unused imports warnings when compiling in test mode
    #[test]
    fn execute_repl_help() {
        super::main();
    }
}
<|endoftext|>


<commit_before>#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub struct PresentationContextProposed {
    pub id: u8,
    pub abstract_syntax: String,
    pub transfer_syntaxes: Vec<String>,
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub struct PresentationContextResult {
    pub id: u8,
    pub reason: PresentationContextResultReason,
    pub transfer_syntax: String,
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum PresentationContextResultReason {
    Acceptance = 0,
    UserRejection = 1,
    NoReason = 2,
    AbstractSyntaxNotSupported = 3,
    TransferSyntaxesNotSupported = 4,
}

impl PresentationContextResultReason {
    fn from(reason: u8) -> Option<PresentationContextResultReason> {
        let result = match reason {
            0 => PresentationContextResultReason::Acceptance,
            1 => PresentationContextResultReason::UserRejection,
            2 => PresentationContextResultReason::NoReason,
            3 => PresentationContextResultReason::AbstractSyntaxNotSupported,
            4 => PresentationContextResultReason::TransferSyntaxesNotSupported,
            _ => {
                return None;
            }
        };

        Some(result)
    }
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum AssociationRJResult {
    Permanent,
    Transient,
}

impl AssociationRJResult {
    fn from(value: u8) -> Option<AssociationRJResult> {
        match value {
            0 => Some(AssociationRJResult::Permanent),
            1 => Some(AssociationRJResult::Transient),
            _ => None,
        }
    }
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum AssociationRJSource {
    ServiceUser(AssociationRJServiceUserReason),
    ServiceProviderASCE(AssociationRJServiceProviderASCEReason),
    ServiceProviderPresentation(AssociationRJServiceProviderPresentationReason),
}

impl AssociationRJSource {
    fn from(source: u8, reason: u8) -> Option<AssociationRJSource> {
        let result = match (source, reason) {
            (1, 1) => {
                AssociationRJSource::ServiceUser(AssociationRJServiceUserReason::NoReasonGiven)
            }
            (1, 2) => AssociationRJSource::ServiceUser(
                AssociationRJServiceUserReason::ApplicationContextNameNotSupported,
            ),
            (1, 3) => AssociationRJSource::ServiceUser(
                AssociationRJServiceUserReason::CallingAETitleNotRecognized,
            ),
            (1, x) if x == 4 || x == 5 || x == 6 => {
                AssociationRJSource::ServiceUser(AssociationRJServiceUserReason::Reserved(x))
            }
            (1, 7) => AssociationRJSource::ServiceUser(
                AssociationRJServiceUserReason::CalledAETitleNotRecognized,
            ),
            //(1, 8) | (1, 9) | (1, 10) => {
            (1, x) if x == 8 || x == 9 || x == 10 => {
                AssociationRJSource::ServiceUser(AssociationRJServiceUserReason::Reserved(x))
            }
            (1, _) => {
                return None;
            }
            (2, 1) => AssociationRJSource::ServiceProviderASCE(
                AssociationRJServiceProviderASCEReason::NoReasonGiven,
            ),
            (2, 2) => AssociationRJSource::ServiceProviderASCE(
                AssociationRJServiceProviderASCEReason::ProtocolVersionNotSupported,
            ),
            (2, _) => {
                return None;
            }
            (3, 0) => AssociationRJSource::ServiceProviderPresentation(
                AssociationRJServiceProviderPresentationReason::Reserved(0),
            ),
            (3, 1) => AssociationRJSource::ServiceProviderPresentation(
                AssociationRJServiceProviderPresentationReason::TemporaryCongestion,
            ),
            (3, 2) => AssociationRJSource::ServiceProviderPresentation(
                AssociationRJServiceProviderPresentationReason::LocalLimitExceeded,
            ),
            (3, x) if x == 3 || x == 4 || x == 5 || x == 6 || x == 7 => {
                AssociationRJSource::ServiceProviderPresentation(
                    AssociationRJServiceProviderPresentationReason::Reserved(x),
                )
            }
            _ => {
                return None;
            }
        };
        Some(result)
    }
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum AssociationRJServiceUserReason {
    NoReasonGiven,
    ApplicationContextNameNotSupported,
    CallingAETitleNotRecognized,
    CalledAETitleNotRecognized,
    Reserved(u8),
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum AssociationRJServiceProviderASCEReason {
    NoReasonGiven,
    ProtocolVersionNotSupported,
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum AssociationRJServiceProviderPresentationReason {
    TemporaryCongestion,
    LocalLimitExceeded,
    Reserved(u8),
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub struct PDataValue {
    pub presentation_context_id: u8,
    pub value_type: PDataValueType,
    pub is_last: bool,
    pub data: Vec<u8>,
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum PDataValueType {
    Command,
    Data,
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum AbortRQSource {
    ServiceUser,
    ServiceProvider(AbortRQServiceProviderReason),
    Reserved,
}

impl AbortRQSource {
    fn from(source: u8, reason: u8) -> Option<AbortRQSource> {
        let result = match (source, reason) {
            (0, _) => AbortRQSource::ServiceUser,
            (1, _) => AbortRQSource::Reserved,
            (2, 0) => AbortRQSource::ServiceProvider(
                AbortRQServiceProviderReason::ReasonNotSpecifiedUnrecognizedPdu,
            ),
            (2, 2) => AbortRQSource::ServiceProvider(AbortRQServiceProviderReason::UnexpectedPdu),
            (2, 3) => AbortRQSource::ServiceProvider(AbortRQServiceProviderReason::Reserved),
            (2, 4) => AbortRQSource::ServiceProvider(
                AbortRQServiceProviderReason::UnrecognizedPduParameter,
            ),
            (2, 5) => {
                AbortRQSource::ServiceProvider(AbortRQServiceProviderReason::UnexpectedPduParameter)
            }
            (2, 6) => {
                AbortRQSource::ServiceProvider(AbortRQServiceProviderReason::InvalidPduParameter)
            }
            (_, _) => {
                return None;
            }
        };

        Some(result)
    }
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum AbortRQServiceProviderReason {
    ReasonNotSpecifiedUnrecognizedPdu,
    UnexpectedPdu,
    Reserved,
    UnrecognizedPduParameter,
    UnexpectedPduParameter,
    InvalidPduParameter,
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum PduVariableItem {
    Unknown(u8),
    ApplicationContext(String),
    PresentationContextProposed(PresentationContextProposed),
    PresentationContextResult(PresentationContextResult),
    UserVariables(Vec<UserVariableItem>),
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum UserVariableItem {
    Unknown(u8, Vec<u8>),
    MaxLength(u32),
    ImplementationClassUID(String),
    ImplementationVersionName(String),
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum Pdu {
    Unknown {
        pdu_type: u8,
        data: Vec<u8>,
    },
    AssociationRQ {
        protocol_version: u16,
        calling_ae_title: String,
        called_ae_title: String,
        application_context_name: String,
        presentation_contexts: Vec<PresentationContextProposed>,
        user_variables: Vec<UserVariableItem>,
    },
    AssociationAC {
        protocol_version: u16,
        application_context_name: String,
        presentation_contexts: Vec<PresentationContextResult>,
        user_variables: Vec<UserVariableItem>,
    },
    AssociationRJ {
        result: AssociationRJResult,
        source: AssociationRJSource,
    },
    PData {
        data: Vec<PDataValue>,
    },
    ReleaseRQ,
    ReleaseRP,
    AbortRQ {
        source: AbortRQSource,
    },
}

pub mod reader;
pub mod writer;

#[cfg(test)]
mod test;
<commit_msg>Moved mod declarations.<commit_after>pub mod reader;
pub mod writer;

#[cfg(test)]
mod test;

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub struct PresentationContextProposed {
    pub id: u8,
    pub abstract_syntax: String,
    pub transfer_syntaxes: Vec<String>,
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub struct PresentationContextResult {
    pub id: u8,
    pub reason: PresentationContextResultReason,
    pub transfer_syntax: String,
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum PresentationContextResultReason {
    Acceptance = 0,
    UserRejection = 1,
    NoReason = 2,
    AbstractSyntaxNotSupported = 3,
    TransferSyntaxesNotSupported = 4,
}

impl PresentationContextResultReason {
    fn from(reason: u8) -> Option<PresentationContextResultReason> {
        let result = match reason {
            0 => PresentationContextResultReason::Acceptance,
            1 => PresentationContextResultReason::UserRejection,
            2 => PresentationContextResultReason::NoReason,
            3 => PresentationContextResultReason::AbstractSyntaxNotSupported,
            4 => PresentationContextResultReason::TransferSyntaxesNotSupported,
            _ => {
                return None;
            }
        };

        Some(result)
    }
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum AssociationRJResult {
    Permanent,
    Transient,
}

impl AssociationRJResult {
    fn from(value: u8) -> Option<AssociationRJResult> {
        match value {
            0 => Some(AssociationRJResult::Permanent),
            1 => Some(AssociationRJResult::Transient),
            _ => None,
        }
    }
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum AssociationRJSource {
    ServiceUser(AssociationRJServiceUserReason),
    ServiceProviderASCE(AssociationRJServiceProviderASCEReason),
    ServiceProviderPresentation(AssociationRJServiceProviderPresentationReason),
}

impl AssociationRJSource {
    fn from(source: u8, reason: u8) -> Option<AssociationRJSource> {
        let result = match (source, reason) {
            (1, 1) => {
                AssociationRJSource::ServiceUser(AssociationRJServiceUserReason::NoReasonGiven)
            }
            (1, 2) => AssociationRJSource::ServiceUser(
                AssociationRJServiceUserReason::ApplicationContextNameNotSupported,
            ),
            (1, 3) => AssociationRJSource::ServiceUser(
                AssociationRJServiceUserReason::CallingAETitleNotRecognized,
            ),
            (1, x) if x == 4 || x == 5 || x == 6 => {
                AssociationRJSource::ServiceUser(AssociationRJServiceUserReason::Reserved(x))
            }
            (1, 7) => AssociationRJSource::ServiceUser(
                AssociationRJServiceUserReason::CalledAETitleNotRecognized,
            ),
            //(1, 8) | (1, 9) | (1, 10) => {
            (1, x) if x == 8 || x == 9 || x == 10 => {
                AssociationRJSource::ServiceUser(AssociationRJServiceUserReason::Reserved(x))
            }
            (1, _) => {
                return None;
            }
            (2, 1) => AssociationRJSource::ServiceProviderASCE(
                AssociationRJServiceProviderASCEReason::NoReasonGiven,
            ),
            (2, 2) => AssociationRJSource::ServiceProviderASCE(
                AssociationRJServiceProviderASCEReason::ProtocolVersionNotSupported,
            ),
            (2, _) => {
                return None;
            }
            (3, 0) => AssociationRJSource::ServiceProviderPresentation(
                AssociationRJServiceProviderPresentationReason::Reserved(0),
            ),
            (3, 1) => AssociationRJSource::ServiceProviderPresentation(
                AssociationRJServiceProviderPresentationReason::TemporaryCongestion,
            ),
            (3, 2) => AssociationRJSource::ServiceProviderPresentation(
                AssociationRJServiceProviderPresentationReason::LocalLimitExceeded,
            ),
            (3, x) if x == 3 || x == 4 || x == 5 || x == 6 || x == 7 => {
                AssociationRJSource::ServiceProviderPresentation(
                    AssociationRJServiceProviderPresentationReason::Reserved(x),
                )
            }
            _ => {
                return None;
            }
        };
        Some(result)
    }
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum AssociationRJServiceUserReason {
    NoReasonGiven,
    ApplicationContextNameNotSupported,
    CallingAETitleNotRecognized,
    CalledAETitleNotRecognized,
    Reserved(u8),
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum AssociationRJServiceProviderASCEReason {
    NoReasonGiven,
    ProtocolVersionNotSupported,
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum AssociationRJServiceProviderPresentationReason {
    TemporaryCongestion,
    LocalLimitExceeded,
    Reserved(u8),
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub struct PDataValue {
    pub presentation_context_id: u8,
    pub value_type: PDataValueType,
    pub is_last: bool,
    pub data: Vec<u8>,
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum PDataValueType {
    Command,
    Data,
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum AbortRQSource {
    ServiceUser,
    ServiceProvider(AbortRQServiceProviderReason),
    Reserved,
}

impl AbortRQSource {
    fn from(source: u8, reason: u8) -> Option<AbortRQSource> {
        let result = match (source, reason) {
            (0, _) => AbortRQSource::ServiceUser,
            (1, _) => AbortRQSource::Reserved,
            (2, 0) => AbortRQSource::ServiceProvider(
                AbortRQServiceProviderReason::ReasonNotSpecifiedUnrecognizedPdu,
            ),
            (2, 2) => AbortRQSource::ServiceProvider(AbortRQServiceProviderReason::UnexpectedPdu),
            (2, 3) => AbortRQSource::ServiceProvider(AbortRQServiceProviderReason::Reserved),
            (2, 4) => AbortRQSource::ServiceProvider(
                AbortRQServiceProviderReason::UnrecognizedPduParameter,
            ),
            (2, 5) => {
                AbortRQSource::ServiceProvider(AbortRQServiceProviderReason::UnexpectedPduParameter)
            }
            (2, 6) => {
                AbortRQSource::ServiceProvider(AbortRQServiceProviderReason::InvalidPduParameter)
            }
            (_, _) => {
                return None;
            }
        };

        Some(result)
    }
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum AbortRQServiceProviderReason {
    ReasonNotSpecifiedUnrecognizedPdu,
    UnexpectedPdu,
    Reserved,
    UnrecognizedPduParameter,
    UnexpectedPduParameter,
    InvalidPduParameter,
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum PduVariableItem {
    Unknown(u8),
    ApplicationContext(String),
    PresentationContextProposed(PresentationContextProposed),
    PresentationContextResult(PresentationContextResult),
    UserVariables(Vec<UserVariableItem>),
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum UserVariableItem {
    Unknown(u8, Vec<u8>),
    MaxLength(u32),
    ImplementationClassUID(String),
    ImplementationVersionName(String),
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Debug)]
pub enum Pdu {
    Unknown {
        pdu_type: u8,
        data: Vec<u8>,
    },
    AssociationRQ {
        protocol_version: u16,
        calling_ae_title: String,
        called_ae_title: String,
        application_context_name: String,
        presentation_contexts: Vec<PresentationContextProposed>,
        user_variables: Vec<UserVariableItem>,
    },
    AssociationAC {
        protocol_version: u16,
        application_context_name: String,
        presentation_contexts: Vec<PresentationContextResult>,
        user_variables: Vec<UserVariableItem>,
    },
    AssociationRJ {
        result: AssociationRJResult,
        source: AssociationRJSource,
    },
    PData {
        data: Vec<PDataValue>,
    },
    ReleaseRQ,
    ReleaseRP,
    AbortRQ {
        source: AbortRQSource,
    },
}<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashSet};

use reqwest::Url;
use serde::Deserialize;
use serde_json::Value;

/// A Rosetta Code task.
#[derive(Clone, PartialEq, Eq, Hash, Debug, Deserialize)]
pub struct Task {
    /// The ID of the page containing the task in the MediaWiki API.
    #[serde(rename = "pageid")]
    pub id: u64,

    /// The human-readable title of the task.
    pub title: String,
}

/// Encapsulates errors that might occur during JSON parsing.
#[derive(Debug)]
enum TaskParseError {
    /// Something went wrong with the HTTP request to the API.
    Http(reqwest::Error),

    /// Could not parse a URL
    Url(reqwest::UrlError),

    /// There was a problem parsing the API response into JSON.
    Json(serde_json::Error),

    /// The response JSON contained unexpected keys or values.
    UnexpectedFormat,
}

impl From<serde_json::Error> for TaskParseError {
    fn from(err: serde_json::Error) -> Self {
        TaskParseError::Json(err)
    }
}

impl From<reqwest::UrlError> for TaskParseError {
    fn from(err: reqwest::UrlError) -> Self {
        TaskParseError::Url(err)
    }
}

impl From<reqwest::Error> for TaskParseError {
    fn from(err: reqwest::Error) -> Self {
        TaskParseError::Http(err)
    }
}

/// Represents a category of pages on Rosetta Code, such as "Rust".
struct Category {
    name: String,
    continue_params: Option<BTreeMap<String, String>>,
}

impl Category {
    fn new(name: &str) -> Category {
        let mut continue_params = BTreeMap::new();
        continue_params.insert("continue".to_owned(), "".to_owned());

        Category {
            name: name.to_owned(),
            continue_params: Some(continue_params),
        }
    }
}

/// Sends a request to Rosetta Code through the MediaWiki API. If successful, returns the response
/// as a JSON object.
fn query_api(
    category_name: &str,
    continue_params: &BTreeMap<String, String>,
) -> Result<Value, TaskParseError> {
    let mut url = Url::parse("http://rosettacode.org/mw/api.php")?;
    url.query_pairs_mut()
        .append_pair("action", "query")
        .append_pair("list", "categorymembers")
        .append_pair("cmtitle", &format!("Category:{}", category_name))
        .append_pair("cmlimit", "500")
        .append_pair("format", "json")
        .extend_pairs(continue_params);

    Ok(reqwest::get(url)?.json()?)
}

/// Given a JSON object, parses the task information from the MediaWiki API response.
fn parse_tasks(json: &Value) -> Result<Vec<Task>, TaskParseError> {
    let tasks_json = json
        .pointer("/query/categorymembers")
        .and_then(Value::as_array)
        .ok_or(TaskParseError::UnexpectedFormat)?;

    tasks_json
        .iter()
        .map(|json| Task::deserialize(json).map_err(From::from))
        .collect()
}

impl Iterator for Category {
    type Item = Vec<Task>;

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

        query_api(&self.name, self.continue_params.as_ref().unwrap())
            .and_then(|result| {
                // If there are more pages of results to request, save them for the next iteration.
                self.continue_params =
                    result
                        .get("continue")
                        .and_then(Value::as_object)
                        .map(|continue_params| {
                            continue_params
                                .iter()
                                .map(|(key, value)| {
                                    (key.to_owned(), value.as_str().unwrap().to_owned())
                                })
                                .collect()
                        });

                parse_tasks(&result)
            })
            .map_err(|err| println!("Error parsing response: {:?}", err))
            .ok()
    }
}

pub fn all_tasks() -> Vec<Task> {
    Category::new("Programming Tasks")
        .flat_map(|tasks| tasks)
        .collect()
}

pub fn unimplemented_tasks(lang: &str) -> Vec<Task> {
    let all_tasks = all_tasks().iter().cloned().collect::<HashSet<_>>();
    let implemented_tasks = Category::new(lang)
        .flat_map(|tasks| tasks)
        .collect::<HashSet<_>>();
    let mut unimplemented_tasks = all_tasks
        .difference(&implemented_tasks)
        .cloned()
        .collect::<Vec<Task>>();
    unimplemented_tasks.sort_by(|a, b| a.title.cmp(&b.title));
    unimplemented_tasks
}
<commit_msg>apply a few clippy lints<commit_after>use std::collections::{BTreeMap, HashSet};

use reqwest::Url;
use serde::Deserialize;
use serde_json::Value;

/// A Rosetta Code task.
#[derive(Clone, PartialEq, Eq, Hash, Debug, Deserialize)]
pub struct Task {
    /// The ID of the page containing the task in the MediaWiki API.
    #[serde(rename = "pageid")]
    pub id: u64,

    /// The human-readable title of the task.
    pub title: String,
}

/// Encapsulates errors that might occur during JSON parsing.
#[derive(Debug)]
enum TaskParseError {
    /// Something went wrong with the HTTP request to the API.
    Http(reqwest::Error),

    /// Could not parse a URL
    Url(reqwest::UrlError),

    /// There was a problem parsing the API response into JSON.
    Json(serde_json::Error),

    /// The response JSON contained unexpected keys or values.
    UnexpectedFormat,
}

impl From<serde_json::Error> for TaskParseError {
    fn from(err: serde_json::Error) -> Self {
        TaskParseError::Json(err)
    }
}

impl From<reqwest::UrlError> for TaskParseError {
    fn from(err: reqwest::UrlError) -> Self {
        TaskParseError::Url(err)
    }
}

impl From<reqwest::Error> for TaskParseError {
    fn from(err: reqwest::Error) -> Self {
        TaskParseError::Http(err)
    }
}

/// Represents a category of pages on Rosetta Code, such as "Rust".
struct Category {
    name: String,
    continue_params: Option<BTreeMap<String, String>>,
}

impl Category {
    fn new(name: &str) -> Category {
        let mut continue_params = BTreeMap::new();
        continue_params.insert("continue".to_owned(), "".to_owned());

        Category {
            name: name.to_owned(),
            continue_params: Some(continue_params),
        }
    }
}

/// Sends a request to Rosetta Code through the MediaWiki API. If successful, returns the response
/// as a JSON object.
fn query_api(
    category_name: &str,
    continue_params: &BTreeMap<String, String>,
) -> Result<Value, TaskParseError> {
    let mut url = Url::parse("http://rosettacode.org/mw/api.php")?;
    url.query_pairs_mut()
        .append_pair("action", "query")
        .append_pair("list", "categorymembers")
        .append_pair("cmtitle", &format!("Category:{}", category_name))
        .append_pair("cmlimit", "500")
        .append_pair("format", "json")
        .extend_pairs(continue_params);

    Ok(reqwest::get(url)?.json()?)
}

/// Given a JSON object, parses the task information from the MediaWiki API response.
fn parse_tasks(json: &Value) -> Result<Vec<Task>, TaskParseError> {
    let tasks_json = json
        .pointer("/query/categorymembers")
        .and_then(Value::as_array)
        .ok_or(TaskParseError::UnexpectedFormat)?;

    tasks_json
        .iter()
        .map(|json| Task::deserialize(json).map_err(From::from))
        .collect()
}

impl Iterator for Category {
    type Item = Vec<Task>;

    fn next(&mut self) -> Option<Self::Item> {
        self.continue_params.as_ref()?;

        query_api(&self.name, self.continue_params.as_ref().unwrap())
            .and_then(|result| {
                // If there are more pages of results to request, save them for the next iteration.
                self.continue_params =
                    result
                        .get("continue")
                        .and_then(Value::as_object)
                        .map(|continue_params| {
                            continue_params
                                .iter()
                                .map(|(key, value)| {
                                    (key.to_owned(), value.as_str().unwrap().to_owned())
                                })
                                .collect()
                        });

                parse_tasks(&result)
            })
            .map_err(|err| println!("Error parsing response: {:?}", err))
            .ok()
    }
}

pub fn all_tasks() -> Vec<Task> {
    Category::new("Programming Tasks")
        .flatten()
        .collect()
}

pub fn unimplemented_tasks(lang: &str) -> Vec<Task> {
    let all_tasks = all_tasks().iter().cloned().collect::<HashSet<_>>();
    let implemented_tasks = Category::new(lang)
        .flatten()
        .collect::<HashSet<_>>();
    let mut unimplemented_tasks = all_tasks
        .difference(&implemented_tasks)
        .cloned()
        .collect::<Vec<Task>>();
    unimplemented_tasks.sort_by(|a, b| a.title.cmp(&b.title));
    unimplemented_tasks
}
<|endoftext|>