<commit_before>use crate::{db::RootDatabase, FileId};
use hir::{HirDisplay, Ty};
use ra_syntax::ast::Pat;
use ra_syntax::{
    algo::visit::{visitor, Visitor},
    ast::{self, PatKind, TypeAscriptionOwner},
    AstNode, SmolStr, SourceFile, SyntaxNode, TextRange,
};

#[derive(Debug, PartialEq, Eq)]
pub enum InlayKind {
    LetBinding,
    ClosureParameter,
}

#[derive(Debug)]
pub struct InlayHint {
    pub range: TextRange,
    pub text: SmolStr,
    pub inlay_kind: InlayKind,
    pub inlay_type_string: String,
}

pub(crate) fn inlay_hints(db: &RootDatabase, file_id: FileId, file: &SourceFile) -> Vec<InlayHint> {
    file.syntax()
        .descendants()
        .map(|node| get_inlay_hints(db, file_id, &node).unwrap_or_default())
        .flatten()
        .collect()
}

fn get_inlay_hints(
    db: &RootDatabase,
    file_id: FileId,
    node: &SyntaxNode,
) -> Option<Vec<InlayHint>> {
    visitor()
        .visit(|let_statement: ast::LetStmt| {
            let let_syntax = let_statement.syntax();

            if let_statement.ascribed_type().is_some() {
                return None;
            }

            let let_pat = let_statement.pat()?;
            let inlay_type_string = get_node_displayable_type(db, file_id, let_syntax, &let_pat)?
                .display(db)
                .to_string();;

            let pat_range = match let_pat.kind() {
                PatKind::BindPat(bind_pat) => bind_pat.syntax().text_range(),
                PatKind::TuplePat(tuple_pat) => tuple_pat.syntax().text_range(),
                _ => return None,
            };

            Some(vec![InlayHint {
                range: pat_range,
                text: let_syntax.text().to_string().into(),
                inlay_kind: InlayKind::LetBinding,
                inlay_type_string,
            }])
        })
        .visit(|closure_parameter: ast::LambdaExpr| match closure_parameter.param_list() {
            Some(param_list) => Some(
                param_list
                    .params()
                    .filter(|closure_param| closure_param.ascribed_type().is_none())
                    .filter_map(|closure_param| {
                        let closure_param_syntax = closure_param.syntax();
                        let inlay_type_string = get_node_displayable_type(
                            db,
                            file_id,
                            closure_param_syntax,
                            &closure_param.pat()?,
                        )?
                        .display(db)
                        .to_string();
                        Some(InlayHint {
                            range: closure_param_syntax.text_range(),
                            text: closure_param_syntax.text().to_string().into(),
                            inlay_kind: InlayKind::ClosureParameter,
                            inlay_type_string,
                        })
                    })
                    .collect(),
            ),
            None => None,
        })
        .accept(&node)?
}

fn get_node_displayable_type(
    db: &RootDatabase,
    file_id: FileId,
    node_syntax: &SyntaxNode,
    node_pat: &Pat,
) -> Option<Ty> {
    let analyzer = hir::SourceAnalyzer::new(db, file_id, node_syntax, None);
    analyzer.type_of_pat(db, node_pat).and_then(|resolved_type| {
        if let Ty::Apply(_) = resolved_type {
            Some(resolved_type)
        } else {
            None
        }
    })
}

#[cfg(test)]
mod tests {
    use crate::mock_analysis::single_file;
    use insta::assert_debug_snapshot_matches;

    #[test]
    fn test_inlay_hints() {
        let (analysis, file_id) = single_file(
            r#"
struct OuterStruct {}

fn main() {
    struct InnerStruct {}

    let test = 54;
    let test = InnerStruct {};
    let test = OuterStruct {};
    let test = vec![222];
    let mut test = Vec::new();
    test.push(333);
    let test = test.into_iter().map(|i| i * i).collect::<Vec<_>>();
    let mut test = 33;
    let _ = 22;
    let test: Vec<_> = (0..3).collect();

    let _ = (0..23).map(|i: u32| {
        let i_squared = i * i;
        i_squared
    });

    let test: i32 = 33;

    let (x, c) = (42, 'a');
    let test = (42, 'a');
}
"#,
        );

        assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[
    InlayHint {
        range: [71; 75),
        text: "let test = 54;",
        inlay_kind: LetBinding,
        inlay_type_string: "i32",
    },
    InlayHint {
        range: [121; 125),
        text: "let test = OuterStruct {};",
        inlay_kind: LetBinding,
        inlay_type_string: "OuterStruct",
    },
    InlayHint {
        range: [297; 305),
        text: "let mut test = 33;",
        inlay_kind: LetBinding,
        inlay_type_string: "i32",
    },
    InlayHint {
        range: [417; 426),
        text: "let i_squared = i * i;",
        inlay_kind: LetBinding,
        inlay_type_string: "u32",
    },
    InlayHint {
        range: [496; 502),
        text: "let (x, c) = (42, \'a\');",
        inlay_kind: LetBinding,
        inlay_type_string: "(i32, char)",
    },
    InlayHint {
        range: [524; 528),
        text: "let test = (42, \'a\');",
        inlay_kind: LetBinding,
        inlay_type_string: "(i32, char)",
    },
]"#
        );
    }
}
<commit_msg>Use SmolStr for the type text<commit_after>use crate::{db::RootDatabase, FileId};
use hir::{HirDisplay, Ty};
use ra_syntax::ast::Pat;
use ra_syntax::{
    algo::visit::{visitor, Visitor},
    ast::{self, PatKind, TypeAscriptionOwner},
    AstNode, SmolStr, SourceFile, SyntaxNode, TextRange,
};

#[derive(Debug, PartialEq, Eq)]
pub enum InlayKind {
    LetBinding,
    ClosureParameter,
}

#[derive(Debug)]
pub struct InlayHint {
    pub range: TextRange,
    pub text: SmolStr,
    pub inlay_kind: InlayKind,
    pub inlay_type_string: SmolStr,
}

pub(crate) fn inlay_hints(db: &RootDatabase, file_id: FileId, file: &SourceFile) -> Vec<InlayHint> {
    file.syntax()
        .descendants()
        .map(|node| get_inlay_hints(db, file_id, &node).unwrap_or_default())
        .flatten()
        .collect()
}

fn get_inlay_hints(
    db: &RootDatabase,
    file_id: FileId,
    node: &SyntaxNode,
) -> Option<Vec<InlayHint>> {
    visitor()
        .visit(|let_statement: ast::LetStmt| {
            let let_syntax = let_statement.syntax();

            if let_statement.ascribed_type().is_some() {
                return None;
            }

            let let_pat = let_statement.pat()?;
            let inlay_type_string = get_node_displayable_type(db, file_id, let_syntax, &let_pat)?
                .display(db)
                .to_string()
                .into();

            let pat_range = match let_pat.kind() {
                PatKind::BindPat(bind_pat) => bind_pat.syntax().text_range(),
                PatKind::TuplePat(tuple_pat) => tuple_pat.syntax().text_range(),
                _ => return None,
            };

            Some(vec![InlayHint {
                range: pat_range,
                text: let_syntax.text().to_string().into(),
                inlay_kind: InlayKind::LetBinding,
                inlay_type_string,
            }])
        })
        .visit(|closure_parameter: ast::LambdaExpr| match closure_parameter.param_list() {
            Some(param_list) => Some(
                param_list
                    .params()
                    .filter(|closure_param| closure_param.ascribed_type().is_none())
                    .filter_map(|closure_param| {
                        let closure_param_syntax = closure_param.syntax();
                        let inlay_type_string = get_node_displayable_type(
                            db,
                            file_id,
                            closure_param_syntax,
                            &closure_param.pat()?,
                        )?
                        .display(db)
                        .to_string()
                        .into();

                        Some(InlayHint {
                            range: closure_param_syntax.text_range(),
                            text: closure_param_syntax.text().to_string().into(),
                            inlay_kind: InlayKind::ClosureParameter,
                            inlay_type_string,
                        })
                    })
                    .collect(),
            ),
            None => None,
        })
        .accept(&node)?
}

fn get_node_displayable_type(
    db: &RootDatabase,
    file_id: FileId,
    node_syntax: &SyntaxNode,
    node_pat: &Pat,
) -> Option<Ty> {
    let analyzer = hir::SourceAnalyzer::new(db, file_id, node_syntax, None);
    analyzer.type_of_pat(db, node_pat).and_then(|resolved_type| {
        if let Ty::Apply(_) = resolved_type {
            Some(resolved_type)
        } else {
            None
        }
    })
}

#[cfg(test)]
mod tests {
    use crate::mock_analysis::single_file;
    use insta::assert_debug_snapshot_matches;

    #[test]
    fn test_inlay_hints() {
        let (analysis, file_id) = single_file(
            r#"
struct OuterStruct {}

fn main() {
    struct InnerStruct {}

    let test = 54;
    let test = InnerStruct {};
    let test = OuterStruct {};
    let test = vec![222];
    let mut test = Vec::new();
    test.push(333);
    let test = test.into_iter().map(|i| i * i).collect::<Vec<_>>();
    let mut test = 33;
    let _ = 22;
    let test: Vec<_> = (0..3).collect();

    let _ = (0..23).map(|i: u32| {
        let i_squared = i * i;
        i_squared
    });

    let test: i32 = 33;

    let (x, c) = (42, 'a');
    let test = (42, 'a');
}
"#,
        );

        assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[
    InlayHint {
        range: [71; 75),
        text: "let test = 54;",
        inlay_kind: LetBinding,
        inlay_type_string: "i32",
    },
    InlayHint {
        range: [121; 125),
        text: "let test = OuterStruct {};",
        inlay_kind: LetBinding,
        inlay_type_string: "OuterStruct",
    },
    InlayHint {
        range: [297; 305),
        text: "let mut test = 33;",
        inlay_kind: LetBinding,
        inlay_type_string: "i32",
    },
    InlayHint {
        range: [417; 426),
        text: "let i_squared = i * i;",
        inlay_kind: LetBinding,
        inlay_type_string: "u32",
    },
    InlayHint {
        range: [496; 502),
        text: "let (x, c) = (42, \'a\');",
        inlay_kind: LetBinding,
        inlay_type_string: "(i32, char)",
    },
    InlayHint {
        range: [524; 528),
        text: "let test = (42, \'a\');",
        inlay_kind: LetBinding,
        inlay_type_string: "(i32, char)",
    },
]"#
        );
    }
}
<|endoftext|>


<commit_before>use super::*;

#[derive(Default, Debug)]
pub struct BLinkMaterializer {
    // TODO use interval-based tracking to handle race conditions in
    // hoists where higher is not later.
    pub(super) roots: Mutex<Vec<(PageID, PageID)>>,
}

impl Materializer for BLinkMaterializer {
    type PageFrag = Frag;

    // a vector of (root, prev root) for deterministic recovery
    type Recovery = Vec<(PageID, PageID)>;

    fn new(last_roots: &Option<Self::Recovery>) -> Self {
        let roots: Vec<(PageID, PageID)> =
            last_roots.clone().unwrap_or_else(|| vec![]);

        BLinkMaterializer {
            roots: Mutex::new(roots),
        }
    }

    fn merge(&self, frags: &[&Frag]) -> Frag {
        let (mut base_node, is_root) = match frags[0].clone() {
            Frag::Base(base_node, is_root) => (base_node, is_root),
            _ => panic!("non-Base in first element of frags slice"),
        };

        for &frag in &frags[1..] {
            base_node.apply(frag);
        }

        Frag::Base(base_node, is_root)
    }

    fn recover(&self, frag: &Frag) -> Option<Vec<(PageID, PageID)>> {
        match *frag {
            Frag::Base(ref node, prev_root) => {
                if let Some(prev_root) = prev_root {
                    let mut roots = self.roots.lock().unwrap();
                    if roots.contains(&(node.id, prev_root)) {
                        None
                    } else {
                        roots.push((node.id, prev_root));
                        Some(roots.clone())
                    }
                } else {
                    None
                }
            }
            _ => None,
        }
    }
}
<commit_msg>Update materializer.rs<commit_after>use super::*;

#[derive(Default, Debug)]
pub struct BLinkMaterializer {
    pub(super) roots: Mutex<Vec<(PageID, PageID)>>,
}

impl Materializer for BLinkMaterializer {
    type PageFrag = Frag;

    // a vector of (root, prev root) for deterministic recovery
    type Recovery = Vec<(PageID, PageID)>;

    fn new(last_roots: &Option<Self::Recovery>) -> Self {
        let roots: Vec<(PageID, PageID)> =
            last_roots.clone().unwrap_or_else(|| vec![]);

        BLinkMaterializer {
            roots: Mutex::new(roots),
        }
    }

    fn merge(&self, frags: &[&Frag]) -> Frag {
        let (mut base_node, is_root) = match frags[0].clone() {
            Frag::Base(base_node, is_root) => (base_node, is_root),
            _ => panic!("non-Base in first element of frags slice"),
        };

        for &frag in &frags[1..] {
            base_node.apply(frag);
        }

        Frag::Base(base_node, is_root)
    }

    fn recover(&self, frag: &Frag) -> Option<Vec<(PageID, PageID)>> {
        match *frag {
            Frag::Base(ref node, prev_root) => {
                if let Some(prev_root) = prev_root {
                    let mut roots = self.roots.lock().unwrap();
                    if roots.contains(&(node.id, prev_root)) {
                        None
                    } else {
                        roots.push((node.id, prev_root));
                        Some(roots.clone())
                    }
                } else {
                    None
                }
            }
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use crate::backend::Backend;
use crate::expression::*;
use crate::query_builder::*;
use crate::query_dsl::RunQueryDsl;
use crate::result::QueryResult;
use crate::sql_types::{DieselNumericOps, SqlType};

#[derive(Debug, Clone, DieselNumericOps)]
#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
/// Returned by the [`sql()`] function.
///
/// [`sql()`]: ../dsl/fn.sql.html
pub struct SqlLiteral<ST, T = ()> {
    sql: String,
    inner: T,
    _marker: PhantomData<ST>,
}

impl<ST, T> SqlLiteral<ST, T>
where
    ST: TypedExpressionType,
{
    #[doc(hidden)]
    pub fn new(sql: String, inner: T) -> Self {
        SqlLiteral {
            sql: sql,
            inner: inner,
            _marker: PhantomData,
        }
    }

    /// Bind a value for use with this SQL query.
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::{Integer, Text, Bool};
    /// #     let connection = establish_connection();
    /// let seans_id = users
    ///     .select(id)
    ///     .filter(sql::<Bool>("name = ").bind::<Text, _>("Sean"))
    ///     .get_result(&connection);
    /// assert_eq!(Ok(1), seans_id);
    ///
    /// let tess_id = sql::<Integer>("SELECT id FROM users WHERE name = ")
    ///     .bind::<Text, _>("Tess")
    ///     .get_result(&connection);
    /// assert_eq!(Ok(2), tess_id);
    /// # }
    /// ```
    ///
    /// ### Multiple Bind Params
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::{Integer, Text, Bool};
    /// #     let connection = establish_connection();
    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
    /// #           .execute(&connection).unwrap();
    /// let query = users
    ///     .select(name)
    ///     .filter(
    ///         sql::<Bool>("id > ")
    ///         .bind::<Integer,_>(1)
    ///         .sql(" AND name <> ")
    ///         .bind::<Text, _>("Ryan")
    ///     )
    ///     .get_results(&connection);
    /// let expected = vec!["Tess".to_string()];
    /// assert_eq!(Ok(expected), query);
    /// # }
    /// ```
    pub fn bind<BindST, U>(self, bind_value: U) -> UncheckedBind<Self, U::Expression>
    where
        BindST: SqlType + TypedExpressionType,
        U: AsExpression<BindST>,
    {
        UncheckedBind::new(self, bind_value.as_expression())
    }

    /// Use literal SQL in the query builder
    ///
    /// This function is intended for use when you need a small bit of raw SQL in
    /// your query. If you want to write the entire query using raw SQL, use
    /// [`sql_query`](../fn.sql_query.html) instead.
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::Bool;
    /// #     let connection = establish_connection();
    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
    /// #           .execute(&connection).unwrap();
    /// let query = users
    ///     .select(name)
    ///     .filter(
    ///         sql::<Bool>("id > 1")
    ///         .sql(" AND name <> 'Ryan'")
    ///     )
    ///     .get_results(&connection);
    /// let expected = vec!["Tess".to_string()];
    /// assert_eq!(Ok(expected), query);
    /// # }
    /// ```
    pub fn sql(self, sql: &str) -> SqlLiteral<ST, Self> {
        SqlLiteral::new(sql.into(), self)
    }
}

impl<ST, T> Expression for SqlLiteral<ST, T>
where
    ST: TypedExpressionType,
{
    type SqlType = ST;
}

impl<ST, T, DB> QueryFragment<DB> for SqlLiteral<ST, T>
where
    DB: Backend,
    T: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.inner.walk_ast(out.reborrow())?;
        out.push_sql(&self.sql);
        Ok(())
    }
}

impl<ST, T> QueryId for SqlLiteral<ST, T> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<ST, T> Query for SqlLiteral<ST, T>
where
    Self: Expression,
{
    type SqlType = ST;
}

impl<ST, T, Conn> RunQueryDsl<Conn> for SqlLiteral<ST, T> {}

impl<QS, ST, T> SelectableExpression<QS> for SqlLiteral<ST, T> where Self: Expression {}

impl<QS, ST, T> AppearsOnTable<QS> for SqlLiteral<ST, T> where Self: Expression {}

impl<ST, T, GB> ValidGrouping<GB> for SqlLiteral<ST, T> {
    type IsAggregate = is_aggregate::Never;
}

/// Use literal SQL in the query builder.
///
/// Available for when you truly cannot represent something using the expression
/// DSL. You will need to provide the SQL type of the expression, in addition to
/// the SQL.
///
/// This function is intended for use when you need a small bit of raw SQL in
/// your query. If you want to write the entire query using raw SQL, use
/// [`sql_query`](../fn.sql_query.html) instead.
///
/// Query parameters can be bound into the literal SQL using [`SqlLiteral::bind()`].
///
/// # Safety
///
/// The compiler will be unable to verify the correctness of the annotated type.
/// If you give the wrong type, it'll either return an error when deserializing
/// the query result or produce unexpected values.
///
/// # Examples
///
/// ```rust
/// # include!("../doctest_setup.rs");
/// # fn main() {
/// #     run_test_1().unwrap();
/// #     run_test_2().unwrap();
/// # }
/// #
/// # fn run_test_1() -> QueryResult<()> {
/// #     use schema::users::dsl::*;
/// #     use diesel::sql_types::Bool;
/// use diesel::dsl::sql;
/// #     let connection = establish_connection();
/// let user = users.filter(sql::<Bool>("name = 'Sean'")).first(&connection)?;
/// let expected = (1, String::from("Sean"));
/// assert_eq!(expected, user);
/// #     Ok(())
/// # }
/// #
/// # fn run_test_2() -> QueryResult<()> {
/// #     use schema::users;
/// #     use diesel::sql_types::{Bool, Integer, Text};
/// #     let connection = establish_connection();
/// #     diesel::insert_into(users::table)
/// #         .values(users::name.eq("Jim"))
/// #         .execute(&connection).unwrap();
/// let query = users
///     .select(name)
///     .filter(
///         sql::<Bool>("id > ")
///         .bind::<Integer,_>(1)
///         .sql(" AND name <> ")
///         .bind::<Text, _>("Ryan")
///     )
///     .get_results(&connection);
/// let expected = vec!["Tess".to_string()];
/// assert_eq!(Ok(expected), query);
/// #     Ok(())
/// # }
/// ```
/// [`SqlLiteral::bind()`]: ../expression/struct.SqlLiteral.html#method.bind
pub fn sql<ST>(sql: &str) -> SqlLiteral<ST>
where
    ST: TypedExpressionType,
{
    SqlLiteral::new(sql.into(), ())
}

#[derive(QueryId, Debug, Clone, Copy)]
#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
/// Returned by the [`SqlLiteral::bind()`] method when binding a value to a fragment of SQL.
///
/// [`SqlLiteral::bind()`]: ./struct.SqlLiteral.html#method.bind
pub struct UncheckedBind<Query, Value> {
    query: Query,
    value: Value,
}

impl<Query, Value> UncheckedBind<Query, Value>
where
    Query: Expression,
{
    pub(crate) fn new(query: Query, value: Value) -> Self {
        UncheckedBind { query, value }
    }

    /// Use literal SQL in the query builder.
    ///
    /// This function is intended for use when you need a small bit of raw SQL in
    /// your query. If you want to write the entire query using raw SQL, use
    /// [`sql_query`](../fn.sql_query.html) instead.
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::{Integer, Bool};
    /// #     let connection = establish_connection();
    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
    /// #           .execute(&connection).unwrap();
    /// let query = users
    ///     .select(name)
    ///     .filter(
    ///         sql::<Bool>("id > ")
    ///         .bind::<Integer,_>(1)
    ///         .sql(" AND name <> 'Ryan'")
    ///     )
    ///     .get_results(&connection);
    /// let expected = vec!["Tess".to_string()];
    /// assert_eq!(Ok(expected), query);
    /// # }
    /// ```
    pub fn sql(self, sql: &str) -> SqlLiteral<Query::SqlType, Self> {
        SqlLiteral::new(sql.into(), self)
    }
}

impl<Query, Value> Expression for UncheckedBind<Query, Value>
where
    Query: Expression,
{
    type SqlType = Query::SqlType;
}

impl<Query, Value, DB> QueryFragment<DB> for UncheckedBind<Query, Value>
where
    DB: Backend,
    Query: QueryFragment<DB>,
    Value: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        self.query.walk_ast(out.reborrow())?;
        self.value.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<Q, Value> Query for UncheckedBind<Q, Value>
where
    Q: Query,
{
    type SqlType = Q::SqlType;
}

impl<Query, Value, GB> ValidGrouping<GB> for UncheckedBind<Query, Value> {
    type IsAggregate = is_aggregate::Never;
}

impl<QS, Query, Value> SelectableExpression<QS> for UncheckedBind<Query, Value> where
    Self: AppearsOnTable<QS>
{
}

impl<QS, Query, Value> AppearsOnTable<QS> for UncheckedBind<Query, Value> where Self: Expression {}

impl<Query, Value, Conn> RunQueryDsl<Conn> for UncheckedBind<Query, Value> {}
<commit_msg>Fix warning raised by GitHub checks<commit_after>use std::marker::PhantomData;

use crate::backend::Backend;
use crate::expression::*;
use crate::query_builder::*;
use crate::query_dsl::RunQueryDsl;
use crate::result::QueryResult;
use crate::sql_types::{DieselNumericOps, SqlType};

#[derive(Debug, Clone, DieselNumericOps)]
#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
/// Returned by the [`sql()`] function.
///
/// [`sql()`]: ../dsl/fn.sql.html
pub struct SqlLiteral<ST, T = ()> {
    sql: String,
    inner: T,
    _marker: PhantomData<ST>,
}

impl<ST, T> SqlLiteral<ST, T>
where
    ST: TypedExpressionType,
{
    #[doc(hidden)]
    pub fn new(sql: String, inner: T) -> Self {
        SqlLiteral {
            sql: sql,
            inner: inner,
            _marker: PhantomData,
        }
    }

    /// Bind a value for use with this SQL query.
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::{Integer, Text, Bool};
    /// #     let connection = establish_connection();
    /// let seans_id = users
    ///     .select(id)
    ///     .filter(sql::<Bool>("name = ").bind::<Text, _>("Sean"))
    ///     .get_result(&connection);
    /// assert_eq!(Ok(1), seans_id);
    ///
    /// let tess_id = sql::<Integer>("SELECT id FROM users WHERE name = ")
    ///     .bind::<Text, _>("Tess")
    ///     .get_result(&connection);
    /// assert_eq!(Ok(2), tess_id);
    /// # }
    /// ```
    ///
    /// ### Multiple Bind Params
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::{Integer, Text, Bool};
    /// #     let connection = establish_connection();
    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
    /// #           .execute(&connection).unwrap();
    /// let query = users
    ///     .select(name)
    ///     .filter(
    ///         sql::<Bool>("id > ")
    ///         .bind::<Integer,_>(1)
    ///         .sql(" AND name <> ")
    ///         .bind::<Text, _>("Ryan")
    ///     )
    ///     .get_results(&connection);
    /// let expected = vec!["Tess".to_string()];
    /// assert_eq!(Ok(expected), query);
    /// # }
    /// ```
    pub fn bind<BindST, U>(self, bind_value: U) -> UncheckedBind<Self, U::Expression>
    where
        BindST: SqlType + TypedExpressionType,
        U: AsExpression<BindST>,
    {
        UncheckedBind::new(self, bind_value.as_expression())
    }

    /// Use literal SQL in the query builder
    ///
    /// This function is intended for use when you need a small bit of raw SQL in
    /// your query. If you want to write the entire query using raw SQL, use
    /// [`sql_query`](../fn.sql_query.html) instead.
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::Bool;
    /// #     let connection = establish_connection();
    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
    /// #           .execute(&connection).unwrap();
    /// let query = users
    ///     .select(name)
    ///     .filter(
    ///         sql::<Bool>("id > 1")
    ///         .sql(" AND name <> 'Ryan'")
    ///     )
    ///     .get_results(&connection);
    /// let expected = vec!["Tess".to_string()];
    /// assert_eq!(Ok(expected), query);
    /// # }
    /// ```
    pub fn sql(self, sql: &str) -> SqlLiteral<ST, Self> {
        SqlLiteral::new(sql.into(), self)
    }
}

impl<ST, T> Expression for SqlLiteral<ST, T>
where
    ST: TypedExpressionType,
{
    type SqlType = ST;
}

impl<ST, T, DB> QueryFragment<DB> for SqlLiteral<ST, T>
where
    DB: Backend,
    T: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.inner.walk_ast(out.reborrow())?;
        out.push_sql(&self.sql);
        Ok(())
    }
}

impl<ST, T> QueryId for SqlLiteral<ST, T> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<ST, T> Query for SqlLiteral<ST, T>
where
    Self: Expression,
{
    type SqlType = ST;
}

impl<ST, T, Conn> RunQueryDsl<Conn> for SqlLiteral<ST, T> {}

impl<QS, ST, T> SelectableExpression<QS> for SqlLiteral<ST, T> where Self: Expression {}

impl<QS, ST, T> AppearsOnTable<QS> for SqlLiteral<ST, T> where Self: Expression {}

impl<ST, T, GB> ValidGrouping<GB> for SqlLiteral<ST, T> {
    type IsAggregate = is_aggregate::Never;
}

/// Use literal SQL in the query builder.
///
/// Available for when you truly cannot represent something using the expression
/// DSL. You will need to provide the SQL type of the expression, in addition to
/// the SQL.
///
/// This function is intended for use when you need a small bit of raw SQL in
/// your query. If you want to write the entire query using raw SQL, use
/// [`sql_query`](../fn.sql_query.html) instead.
///
/// Query parameters can be bound into the literal SQL using [`SqlLiteral::bind()`].
///
/// # Safety
///
/// The compiler will be unable to verify the correctness of the annotated type.
/// If you give the wrong type, it'll either return an error when deserializing
/// the query result or produce unexpected values.
///
/// # Examples
///
/// ```rust
/// # include!("../doctest_setup.rs");
/// # fn main() {
/// #     run_test_1().unwrap();
/// #     run_test_2().unwrap();
/// # }
/// #
/// # fn run_test_1() -> QueryResult<()> {
/// #     use schema::users::dsl::*;
/// #     use diesel::sql_types::Bool;
/// use diesel::dsl::sql;
/// #     let connection = establish_connection();
/// let user = users.filter(sql::<Bool>("name = 'Sean'")).first(&connection)?;
/// let expected = (1, String::from("Sean"));
/// assert_eq!(expected, user);
/// #     Ok(())
/// # }
/// #
/// # fn run_test_2() -> QueryResult<()> {
/// #     use self::users::dsl::*;
/// #     use diesel::dsl::sql;
/// #     use diesel::sql_types::{Bool, Integer, Text};
/// #     let connection = establish_connection();
/// #     diesel::insert_into(users)
/// #         .values(name.eq("Jim"))
/// #         .execute(&connection).unwrap();
/// let query = users
///     .select(name)
///     .filter(
///         sql::<Bool>("id > ")
///         .bind::<Integer,_>(1)
///         .sql(" AND name <> ")
///         .bind::<Text, _>("Ryan")
///     )
///     .get_results(&connection);
/// let expected = vec!["Tess".to_string()];
/// assert_eq!(Ok(expected), query);
/// #     Ok(())
/// # }
/// ```
/// [`SqlLiteral::bind()`]: ../expression/struct.SqlLiteral.html#method.bind
pub fn sql<ST>(sql: &str) -> SqlLiteral<ST>
where
    ST: TypedExpressionType,
{
    SqlLiteral::new(sql.into(), ())
}

#[derive(QueryId, Debug, Clone, Copy)]
#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
/// Returned by the [`SqlLiteral::bind()`] method when binding a value to a fragment of SQL.
///
/// [`SqlLiteral::bind()`]: ./struct.SqlLiteral.html#method.bind
pub struct UncheckedBind<Query, Value> {
    query: Query,
    value: Value,
}

impl<Query, Value> UncheckedBind<Query, Value>
where
    Query: Expression,
{
    pub(crate) fn new(query: Query, value: Value) -> Self {
        UncheckedBind { query, value }
    }

    /// Use literal SQL in the query builder.
    ///
    /// This function is intended for use when you need a small bit of raw SQL in
    /// your query. If you want to write the entire query using raw SQL, use
    /// [`sql_query`](../fn.sql_query.html) instead.
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::{Integer, Bool};
    /// #     let connection = establish_connection();
    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
    /// #           .execute(&connection).unwrap();
    /// let query = users
    ///     .select(name)
    ///     .filter(
    ///         sql::<Bool>("id > ")
    ///         .bind::<Integer,_>(1)
    ///         .sql(" AND name <> 'Ryan'")
    ///     )
    ///     .get_results(&connection);
    /// let expected = vec!["Tess".to_string()];
    /// assert_eq!(Ok(expected), query);
    /// # }
    /// ```
    pub fn sql(self, sql: &str) -> SqlLiteral<Query::SqlType, Self> {
        SqlLiteral::new(sql.into(), self)
    }
}

impl<Query, Value> Expression for UncheckedBind<Query, Value>
where
    Query: Expression,
{
    type SqlType = Query::SqlType;
}

impl<Query, Value, DB> QueryFragment<DB> for UncheckedBind<Query, Value>
where
    DB: Backend,
    Query: QueryFragment<DB>,
    Value: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        self.query.walk_ast(out.reborrow())?;
        self.value.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<Q, Value> Query for UncheckedBind<Q, Value>
where
    Q: Query,
{
    type SqlType = Q::SqlType;
}

impl<Query, Value, GB> ValidGrouping<GB> for UncheckedBind<Query, Value> {
    type IsAggregate = is_aggregate::Never;
}

impl<QS, Query, Value> SelectableExpression<QS> for UncheckedBind<Query, Value> where
    Self: AppearsOnTable<QS>
{
}

impl<QS, Query, Value> AppearsOnTable<QS> for UncheckedBind<Query, Value> where Self: Expression {}

impl<Query, Value, Conn> RunQueryDsl<Conn> for UncheckedBind<Query, Value> {}
<|endoftext|>


<commit_before>#![allow(dead_code, unused_variables)]

use std::collections::HashMap;
use std::fmt;

#[derive(Debug, PartialEq)]
pub struct Source {
    pub nick: String,
    pub ident: Option<String>,
    pub host: Option<String>,
    pub is_server: bool,
}

impl fmt::Display for Source {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.is_server {
            write!(f, ":")?;
        }
        write!(f, "{}", self.nick)?;
        if let Some(ref ident) = self.ident {
            write!(f, "!{}", ident)?;
        }
        if let Some(ref host) = self.host {
            write!(f, "@{}", host)?;
        }

        Ok(())
    }
}

//  <prefix>   ::= <nick> [ '!' <ident>  [ '@' <host> ] ]
impl Source {
    fn parse(s: &str) -> Option<Source> {
        if s.is_empty() {
            return None;
        }

        let (nick, rest) = if let Some(index) = s.find('!') {
            (&s[..index], Some(&s[index + 1..]))
        } else {
            (s, None)
        };

        let (ident, host) = rest
            .map(|r| {
                if let Some(index) = r.find('@') {
                    (Some(&r[..index]), Some(&r[index + 1..]))
                } else {
                    (rest, None)
                }
            })
            .unwrap_or((None, None));

        Some(Source {
            nick: nick.trim_start_matches(':').to_string(),
            ident: ident.map(str::to_string),
            host: host.map(str::to_string),
            is_server: nick.starts_with(':'),
        })
    }
}

#[derive(Debug, PartialEq)]
pub enum MessageKind {
    Away,
    Capability,
    Error,
    Invite,
    Join,
    Kick,
    Mode,
    Nick,
    Notice,
    Numeric(u16),
    Part,
    Pass,
    Ping,
    Pong,
    Privmsg,
    Quit,
    Topic,
    User,
    Unknown,
    Wallops,
}

impl MessageKind {
    pub fn from(msg: &RawMessage) -> MessageKind {
        if let Ok(code) = msg.command.parse::<u16>() {
            return MessageKind::Numeric(code);
        }

        match msg.command.as_str() {
            "CAP" => Self::Capability,
            "JOIN" => Self::Join,
            "KICK" => Self::Kick,
            "MODE" => Self::Mode,
            "NOTICE" => Self::Notice,
            "PART" => Self::Part,
            "PASS" => Self::Pass,
            "PING" => Self::Ping,
            "PONG" => Self::Pong,
            "PRIVMSG" => Self::Privmsg,
            "USER" => Self::User,

            // TODO: Map remaining types
            _ => Self::Unknown,
        }
    }
}

type MessageTags = HashMap<String, MessageTag>;

#[derive(Debug, PartialEq)]
pub struct MessageTag {
    key: String,
    value: Option<String>,
}

#[derive(Debug, PartialEq)]
pub struct RawMessage {
    pub source: Option<Source>,
    pub command: String,
    params: Vec<String>,

    pub timestamp: u64, // TODO: datetime
    pub tags: MessageTags,
}

/// Split `msg` at first space character or end of word if no spaces remain.
fn split_message(msg: &str) -> Option<(&str, &str)> {
    if msg.is_empty() {
        return None;
    }

    match msg.find(' ') {
        Some(index) => Some((&msg[..index], &msg[index + 1..])),
        None => Some((msg, "")),
    }
}

impl RawMessage {
    pub fn new(command: &str, params: &[&str]) -> RawMessage {
        RawMessage {
            command: command.to_string(),
            params: params.iter().map(|s| s.to_string()).collect(),

            source: None,
            timestamp: 0,
            tags: HashMap::new(),
        }
    }

    /// Expects that any trailing CR, LF have been removed.
    ///
    ///  <message>  ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
    ///  <prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
    ///  <command>  ::= <letter> { <letter> } | <number> <number> <number>
    ///  <SPACE>    ::= ' ' { ' ' }
    ///  <params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
    ///  <middle>   ::= <Any *non-empty* sequence of octets not including SPACE
    ///                 or NUL or CR or LF, the first of which may not be ':'>
    ///  <trailing> ::= <Any, possibly *empty*, sequence of octets not including
    ///                   NUL or CR or LF>
    pub fn parse(line: &str) -> Option<Self> {
        let mut line: &str = line;
        let mut msg: Self;

        let tags = if line.starts_with('@') {
            let (tags, rest) = split_message(line)?;
            line = rest;
            // TODO: parse tags
            HashMap::new()
        } else {
            HashMap::new()
        };

        let nick = if line.starts_with(':') {
            let (nick, rest) = split_message(line)?;
            line = rest;
            Some(Source::parse(nick)?)
        } else {
            None
        };

        let (cmd, mut line) = split_message(line)?;

        let mut params: Vec<String> = Vec::new();
        while let Some((param, rest)) = split_message(line) {
            // Trailing param, this will be the end, regardless of
            // remaining whitespace.
            if param.starts_with(':') {
                params.push(line[1..].to_string());
                break;
            } else {
                params.push(param.to_string());
            }

            line = rest;
        }

        Some(Self {
            source: nick,
            command: cmd.to_string(),
            params,
            tags,

            // TODO: pull this out of the tags, if possible
            timestamp: 0,
        })
    }

    pub fn param(&self, i: usize) -> Option<&str> {
        self.params.get(i).map(String::as_ref)
    }

    pub fn trailing(&self) -> Option<&str> {
        self.params.last().map(String::as_ref)
    }
}

impl fmt::Display for RawMessage {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // TOOD: tags

        if let Some(source) = &self.source {
            write!(f, "{} ", source)?;
        }

        write!(f, "{}", self.command)?;

        for (i, param) in self.params.iter().enumerate() {
            // Last is a special case
            if param.contains(' ') {
                write!(f, " :{}", param)?;
            } else {
                write!(f, " {}", param)?;
            }
        }

        Ok(())
    }
}

/// IRC capabilities we support
#[derive(Debug, Hash, PartialEq, Eq)]
pub enum Capability {
    ServerTime,
    Sasl(Vec<String>),
}

impl Capability {
    pub fn from(s: &str) -> Option<Self> {
        let split: Vec<&str> = s.splitn(2, '=').collect();

        let cap = *split.get(0)?;
        let args = split.get(1).unwrap_or(&"").split(',');

        match cap {
            "server-time" => Some(Self::ServerTime),
            "sasl" => {
                let set = args.map(str::to_uppercase).collect();
                Some(Self::Sasl(set))
            }
            _ => None,
        }
    }
}

#[derive(PartialEq, Debug, Clone)]
pub struct ModeSet {
    set: HashMap<char, bool>,
}

impl ModeSet {
    pub fn empty() -> Self {
        Self {
            set: HashMap::new(),
        }
    }

    pub fn apply(&self, s: &str) -> Option<Self> {
        let mut value: Option<bool> = None;
        let mut copy = self.clone();

        for ch in s.chars() {
            match ch {
                '+' => value = Some(true),
                '-' => value = Some(false),
                _ => {
                    if let Some(value) = value {
                        copy.set.insert(ch, value);
                    } else {
                        // Invalid string format, bail early
                        return None;
                    }
                }
            }
        }

        Some(copy)
    }

    pub fn contains(&self, m: char) -> bool {
        self.set.get(&m).map(bool::clone).unwrap_or(false)
    }
}

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

    #[test]
    fn test_parse_mode_string() {
        let modes = ModeSet::empty().apply("-bB+xy");
        let expected = [('b', false), ('B', false), ('x', true), ('y', true)]
            .iter()
            .cloned()
            .collect();

        assert_eq!(modes, Some(ModeSet { set: expected }));
    }

    #[test]
    fn test_parse_caps() {
        assert_eq!(
            Capability::from("server-time"),
            Some(Capability::ServerTime)
        );

        assert_eq!(
            Capability::from("sasl=plain,EXTERNAL"),
            Some(Capability::Sasl(vec![
                "PLAIN".to_string(),
                "EXTERNAL".to_string()
            ]))
        );
    }

    #[test]
    fn test_parse_source() {
        assert_eq!(
            Source::parse("nick!~ident@host").unwrap(),
            Source {
                nick: "nick".to_string(),
                ident: Some("~ident".to_string()),
                host: Some("host".to_string()),
                is_server: false,
            }
        );

        assert_eq!(
            Source::parse("nick!~user").unwrap(),
            Source {
                nick: "nick".to_string(),
                ident: Some("~user".to_string()),
                host: None,
                is_server: false,
            }
        );

        assert_eq!(
            Source::parse("nick").unwrap(),
            Source {
                nick: "nick".to_string(),
                ident: None,
                host: None,
                is_server: false,
            }
        );

        assert_eq!(
            Source::parse(":irc.server!~ident@host").unwrap(),
            Source {
                nick: "irc.server".to_string(),
                ident: Some("~ident".to_string()),
                host: Some("host".to_string()),
                is_server: true,
            }
        );
    }

    #[test]
    fn test_display_source() {
        let cases = vec![
            "nick",
            "nick!~ident",
            "nick!~ident@host",
            ":irc.server!~ident@host",
        ];

        for case in cases {
            let round_trip = format!("{}", Source::parse(case).unwrap());
            assert_eq!(round_trip, case);
        }
    }

    #[test]
    fn test_parse_messages() {
        let line = "@foo=bar :server 001 abc :hello, world";
        let msg = RawMessage::parse(line).expect("failed to parse");

        assert_eq!(msg.command, "001");
        assert_eq!(msg.source.unwrap().nick, "server");
        assert_eq!(msg.params, vec!["abc", "hello, world"]);
        // TODO: wire up assert
    }

    #[test]
    fn test_split_message() {
        assert_eq!(split_message("foo bar baz"), Some(("foo", "bar baz")));
        assert_eq!(split_message("foo bar"), Some(("foo", "bar")));
        assert_eq!(split_message("foo"), Some(("foo", "")));
        assert_eq!(split_message(""), None);
        assert_eq!(split_message("trailing "), Some(("trailing", "")));
        assert_eq!(split_message(" leading"), Some(("", "leading")));
    }
}
<commit_msg>Parse IRCv3 message tags<commit_after>#![allow(dead_code, unused_variables)]

use std::collections::HashMap;
use std::fmt;

#[derive(Debug, PartialEq)]
pub struct Source {
    pub nick: String,
    pub ident: Option<String>,
    pub host: Option<String>,
    pub is_server: bool,
}

impl fmt::Display for Source {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.is_server {
            write!(f, ":")?;
        }
        write!(f, "{}", self.nick)?;
        if let Some(ref ident) = self.ident {
            write!(f, "!{}", ident)?;
        }
        if let Some(ref host) = self.host {
            write!(f, "@{}", host)?;
        }

        Ok(())
    }
}

//  <prefix>   ::= <nick> [ '!' <ident>  [ '@' <host> ] ]
impl Source {
    fn parse(s: &str) -> Option<Source> {
        if s.is_empty() {
            return None;
        }

        let (nick, rest) = if let Some(index) = s.find('!') {
            (&s[..index], Some(&s[index + 1..]))
        } else {
            (s, None)
        };

        let (ident, host) = rest
            .map(|r| {
                if let Some(index) = r.find('@') {
                    (Some(&r[..index]), Some(&r[index + 1..]))
                } else {
                    (rest, None)
                }
            })
            .unwrap_or((None, None));

        Some(Source {
            nick: nick.trim_start_matches(':').to_string(),
            ident: ident.map(str::to_string),
            host: host.map(str::to_string),
            is_server: nick.starts_with(':'),
        })
    }
}

#[derive(Debug, PartialEq)]
pub enum MessageKind {
    Away,
    Capability,
    Error,
    Invite,
    Join,
    Kick,
    Mode,
    Nick,
    Notice,
    Numeric(u16),
    Part,
    Pass,
    Ping,
    Pong,
    Privmsg,
    Quit,
    Topic,
    User,
    Unknown,
    Wallops,
}

impl MessageKind {
    pub fn from(msg: &RawMessage) -> MessageKind {
        if let Ok(code) = msg.command.parse::<u16>() {
            return MessageKind::Numeric(code);
        }

        match msg.command.as_str() {
            "CAP" => Self::Capability,
            "JOIN" => Self::Join,
            "KICK" => Self::Kick,
            "MODE" => Self::Mode,
            "NOTICE" => Self::Notice,
            "PART" => Self::Part,
            "PASS" => Self::Pass,
            "PING" => Self::Ping,
            "PONG" => Self::Pong,
            "PRIVMSG" => Self::Privmsg,
            "USER" => Self::User,
            "ERROR" => Self::Error,
            // TODO: Map remaining types
            _ => Self::Unknown,
        }
    }
}

// <tags>          ::= '@' <tag> [';' <tag>]*
// <tag>           ::= <key> ['=' <escaped value>]
// <key>           ::= [ <vendor> '/' ] <sequence of letters, digits, hyphens (`-`)>
// <escaped value> ::= <sequence of any characters except NUL, CR, LF, semicolon (`;`) and SPACE>
// <vendor>        ::= <host>
#[derive(Debug, PartialEq)]
pub struct Tags {
    inner: HashMap<String, Tag>,
}

impl Tags {
    pub fn empty() -> Self {
        Self {
            inner: HashMap::new(),
        }
    }

    pub fn parse(s: &str) -> Option<Self> {
        if s.chars().next() != Some('@') {
            return None;
        }

        let map = s[1..]
            .split(';')
            .map(Tag::parse)
            .map(|t| (t.key.clone(), t))
            .collect();

        Some(Tags { inner: map })
    }
}

#[derive(Debug, PartialEq)]
pub struct Tag {
    pub key: String,
    pub value: Option<String>,
}

impl Tag {
    pub fn parse(s: &str) -> Self {
        if let Some(idx) = s.find('=') {
            Tag {
                key: s[..idx].to_string(),
                value: Some(s[idx + 1..].to_string()),
            }
        } else {
            Tag {
                key: s.to_string(),
                value: None,
            }
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct RawMessage {
    pub source: Option<Source>,
    pub command: String,
    params: Vec<String>,

    pub timestamp: u64, // TODO: datetime
    pub tags: Tags,
}

/// Split `msg` at first space character or end of word if no spaces remain.
fn split_message(msg: &str) -> Option<(&str, &str)> {
    if msg.is_empty() {
        return None;
    }

    match msg.find(' ') {
        Some(index) => Some((&msg[..index], &msg[index + 1..])),
        None => Some((msg, "")),
    }
}

impl RawMessage {
    pub fn new(command: &str, params: &[&str]) -> RawMessage {
        RawMessage {
            command: command.to_string(),
            params: params.iter().map(|s| s.to_string()).collect(),

            source: None,
            timestamp: 0,
            tags: Tags::empty(),
        }
    }

    /// Expects that any trailing CR, LF have been removed.
    ///
    ///  <message>  ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
    ///  <prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
    ///  <command>  ::= <letter> { <letter> } | <number> <number> <number>
    ///  <SPACE>    ::= ' ' { ' ' }
    ///  <params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
    ///  <middle>   ::= <Any *non-empty* sequence of octets not including SPACE
    ///                 or NUL or CR or LF, the first of which may not be ':'>
    ///  <trailing> ::= <Any, possibly *empty*, sequence of octets not including
    ///                   NUL or CR or LF>
    pub fn parse(line: &str) -> Option<Self> {
        let mut line: &str = line;
        let mut msg: Self;

        let tags = if line.starts_with('@') {
            let (tags, rest) = split_message(line)?;
            line = rest;
            Tags::parse(tags)?
        } else {
            Tags::empty()
        };

        let nick = if line.starts_with(':') {
            let (nick, rest) = split_message(line)?;
            line = rest;
            Some(Source::parse(nick)?)
        } else {
            None
        };

        let (cmd, mut line) = split_message(line)?;

        let mut params: Vec<String> = Vec::new();
        while let Some((param, rest)) = split_message(line) {
            // Trailing param, this will be the end, regardless of
            // remaining whitespace.
            if param.starts_with(':') {
                params.push(line[1..].to_string());
                break;
            } else {
                params.push(param.to_string());
            }

            line = rest;
        }

        Some(Self {
            source: nick,
            command: cmd.to_string(),
            params,
            tags,

            // TODO: pull this out of the tags, if possible
            timestamp: 0,
        })
    }

    pub fn param(&self, i: usize) -> Option<&str> {
        self.params.get(i).map(String::as_ref)
    }

    pub fn trailing(&self) -> Option<&str> {
        self.params.last().map(String::as_ref)
    }
}

impl fmt::Display for RawMessage {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // TOOD: tags

        if let Some(source) = &self.source {
            write!(f, "{} ", source)?;
        }

        write!(f, "{}", self.command)?;

        for (i, param) in self.params.iter().enumerate() {
            // Last is a special case
            if param.contains(' ') {
                write!(f, " :{}", param)?;
            } else {
                write!(f, " {}", param)?;
            }
        }

        Ok(())
    }
}

/// IRC capabilities we support
#[derive(Debug, Hash, PartialEq, Eq)]
pub enum Capability {
    ServerTime,
    Sasl(Vec<String>),
}

impl Capability {
    pub fn from(s: &str) -> Option<Self> {
        let split: Vec<&str> = s.splitn(2, '=').collect();

        let cap = *split.get(0)?;
        let args = split.get(1).unwrap_or(&"").split(',');

        match cap {
            "server-time" => Some(Self::ServerTime),
            "sasl" => {
                let set = args.map(str::to_uppercase).collect();
                Some(Self::Sasl(set))
            }
            _ => None,
        }
    }
}

#[derive(PartialEq, Debug, Clone)]
pub struct ModeSet {
    set: HashMap<char, bool>,
}

impl ModeSet {
    pub fn empty() -> Self {
        Self {
            set: HashMap::new(),
        }
    }

    pub fn apply(&self, s: &str) -> Option<Self> {
        let mut value: Option<bool> = None;
        let mut copy = self.clone();

        for ch in s.chars() {
            match ch {
                '+' => value = Some(true),
                '-' => value = Some(false),
                _ => {
                    if let Some(value) = value {
                        copy.set.insert(ch, value);
                    } else {
                        // Invalid string format, bail early
                        return None;
                    }
                }
            }
        }

        Some(copy)
    }

    pub fn contains(&self, m: char) -> bool {
        self.set.get(&m).map(bool::clone).unwrap_or(false)
    }
}

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

    #[test]
    fn test_parse_mode_string() {
        let modes = ModeSet::empty().apply("-bB+xy");
        let expected = [('b', false), ('B', false), ('x', true), ('y', true)]
            .iter()
            .cloned()
            .collect();

        assert_eq!(modes, Some(ModeSet { set: expected }));
    }

    #[test]
    fn test_parse_caps() {
        assert_eq!(
            Capability::from("server-time"),
            Some(Capability::ServerTime)
        );

        assert_eq!(
            Capability::from("sasl=plain,EXTERNAL"),
            Some(Capability::Sasl(vec![
                "PLAIN".to_string(),
                "EXTERNAL".to_string()
            ]))
        );
    }

    #[test]
    fn test_parse_source() {
        assert_eq!(
            Source::parse("nick!~ident@host").unwrap(),
            Source {
                nick: "nick".to_string(),
                ident: Some("~ident".to_string()),
                host: Some("host".to_string()),
                is_server: false,
            }
        );

        assert_eq!(
            Source::parse("nick!~user").unwrap(),
            Source {
                nick: "nick".to_string(),
                ident: Some("~user".to_string()),
                host: None,
                is_server: false,
            }
        );

        assert_eq!(
            Source::parse("nick").unwrap(),
            Source {
                nick: "nick".to_string(),
                ident: None,
                host: None,
                is_server: false,
            }
        );

        assert_eq!(
            Source::parse(":irc.server!~ident@host").unwrap(),
            Source {
                nick: "irc.server".to_string(),
                ident: Some("~ident".to_string()),
                host: Some("host".to_string()),
                is_server: true,
            }
        );
    }

    #[test]
    fn test_display_source() {
        let cases = vec![
            "nick",
            "nick!~ident",
            "nick!~ident@host",
            ":irc.server!~ident@host",
        ];

        for case in cases {
            let round_trip = format!("{}", Source::parse(case).unwrap());
            assert_eq!(round_trip, case);
        }
    }

    #[test]
    fn test_parse_messages() {
        let line = "@foo=bar :server 001 abc :hello, world";
        let msg = RawMessage::parse(line).expect("failed to parse");

        assert_eq!(msg.command, "001");
        assert_eq!(msg.source.unwrap().nick, "server");
        assert_eq!(msg.params, vec!["abc", "hello, world"]);
        // TODO: wire up assert
    }

    #[test]
    fn test_split_message() {
        assert_eq!(split_message("foo bar baz"), Some(("foo", "bar baz")));
        assert_eq!(split_message("foo bar"), Some(("foo", "bar")));
        assert_eq!(split_message("foo"), Some(("foo", "")));
        assert_eq!(split_message(""), None);
        assert_eq!(split_message("trailing "), Some(("trailing", "")));
        assert_eq!(split_message(" leading"), Some(("", "leading")));
    }

    #[test]
    fn test_parse_tag() {
        let cases = vec![
            (
                "key",
                Tag {
                    key: "key".to_string(),
                    value: None,
                },
            ),
            (
                "key=",
                Tag {
                    key: "key".to_string(),
                    value: Some("".to_string()),
                },
            ),
            (
                "key=val",
                Tag {
                    key: "key".to_string(),
                    value: Some("val".to_string()),
                },
            ),
        ];

        for (input, expected) in cases {
            assert_eq!(Tag::parse(input), expected);
        }
    }

    #[test]
    fn test_parse_tags() {
        let tags = Tags::parse("@foo=bar;baz=;quux");
        let expected = vec![
            (
                "foo".to_string(),
                Tag {
                    key: "foo".to_string(),
                    value: Some("bar".to_string()),
                },
            ),
            (
                "baz".to_string(),
                Tag {
                    key: "baz".to_string(),
                    value: Some("".to_string()),
                },
            ),
            (
                "quux".to_string(),
                Tag {
                    key: "quux".to_string(),
                    value: None,
                },
            ),
        ]
        .into_iter()
        .collect();

        assert_eq!(tags, Some(Tags { inner: expected }));
    }
}
<|endoftext|>


<commit_before>use crate::{Enum, EnumMap};
use core::iter::{Enumerate, FusedIterator};
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::ptr;
use core::slice;

/// Immutable enum map iterator
///
/// This struct is created by `iter` method or `into_iter` on a reference
/// to `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Enum)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     assert_eq!(map[Example::A], 3);
///     for (key, &value) in &map {
///         assert_eq!(value, match key {
///             Example::A => 3,
///             _ => 0,
///         });
///     }
/// }
/// ```
#[derive(Debug)]
pub struct Iter<'a, K, V: 'a> {
    _phantom: PhantomData<fn() -> K>,
    iterator: Enumerate<slice::Iter<'a, V>>,
}

impl<'a, K: Enum<V>, V> Iterator for Iter<'a, K, V> {
    type Item = (K, &'a V);
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator
            .next()
            .map(|(index, item)| (K::from_usize(index), item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }

    fn fold<B, F>(self, init: B, f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        self.iterator
            .map(|(index, item)| (K::from_usize(index), item))
            .fold(init, f)
    }
}

impl<'a, K: Enum<V>, V> DoubleEndedIterator for Iter<'a, K, V> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator
            .next_back()
            .map(|(index, item)| (K::from_usize(index), item))
    }
}

impl<'a, K: Enum<V>, V> ExactSizeIterator for Iter<'a, K, V> {}

impl<'a, K: Enum<V>, V> FusedIterator for Iter<'a, K, V> {}

impl<'a, K: Enum<V>, V> IntoIterator for &'a EnumMap<K, V> {
    type Item = (K, &'a V);
    type IntoIter = Iter<'a, K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        Iter {
            _phantom: PhantomData,
            iterator: self.as_slice().iter().enumerate(),
        }
    }
}

/// Mutable map iterator
///
/// This struct is created by `iter_mut` method or `into_iter` on a mutable
/// reference to `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Debug, Enum)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     for (_, value) in &mut map {
///         *value += 1;
///     }
///     assert_eq!(map, enum_map! { Example::A => 4, _ => 1 });
/// }
/// ```
#[derive(Debug)]
pub struct IterMut<'a, K, V: 'a> {
    _phantom: PhantomData<fn() -> K>,
    iterator: Enumerate<slice::IterMut<'a, V>>,
}

impl<'a, K: Enum<V>, V> Iterator for IterMut<'a, K, V> {
    type Item = (K, &'a mut V);
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator
            .next()
            .map(|(index, item)| (K::from_usize(index), item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }

    fn fold<B, F>(self, init: B, f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        self.iterator
            .map(|(index, item)| (K::from_usize(index), item))
            .fold(init, f)
    }
}

impl<'a, K: Enum<V>, V> DoubleEndedIterator for IterMut<'a, K, V> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator
            .next_back()
            .map(|(index, item)| (K::from_usize(index), item))
    }
}

impl<'a, K: Enum<V>, V> ExactSizeIterator for IterMut<'a, K, V> {}

impl<'a, K: Enum<V>, V> FusedIterator for IterMut<'a, K, V> {}

impl<'a, K: Enum<V>, V> IntoIterator for &'a mut EnumMap<K, V> {
    type Item = (K, &'a mut V);
    type IntoIter = IterMut<'a, K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IterMut {
            _phantom: PhantomData,
            iterator: self.as_mut_slice().iter_mut().enumerate(),
        }
    }
}

/// A map iterator that moves out of map.
///
/// This struct is created by `into_iter` on `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Debug, Enum)]
/// enum Example {
///     A,
///     B,
/// }
///
/// fn main() {
///     let map = enum_map! { Example::A | Example::B => String::from("123") };
///     for (_, value) in map {
///         assert_eq!(value + "4", "1234");
///     }
/// }
/// ```
pub struct IntoIter<K: Enum<V>, V> {
    map: ManuallyDrop<EnumMap<K, V>>,
    position: usize,
}

impl<K: Enum<V>, V> Iterator for IntoIter<K, V> {
    type Item = (K, V);
    fn next(&mut self) -> Option<(K, V)> {
        let slice = self.map.as_slice();
        if self.position < slice.len() {
            let key = K::from_usize(self.position);
            let result = Some((key, unsafe { ptr::read(&slice[self.position]) }));
            self.position += 1;
            result
        } else {
            None
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let slice = self.map.as_slice();
        let diff = slice.len() - self.position;
        (diff, Some(diff))
    }
}

impl<K: Enum<V>, V> ExactSizeIterator for IntoIter<K, V> {}

impl<K: Enum<V>, V> FusedIterator for IntoIter<K, V> {}

impl<K: Enum<V>, V> Drop for IntoIter<K, V> {
    #[inline]
    fn drop(&mut self) {
        for _item in self {}
    }
}

impl<K: Enum<V>, V> IntoIterator for EnumMap<K, V> {
    type Item = (K, V);
    type IntoIter = IntoIter<K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IntoIter {
            map: ManuallyDrop::new(self),
            position: 0,
        }
    }
}

impl<K: Enum<V>, V> EnumMap<K, V> {
    /// An iterator visiting all values. The iterator type is `&V`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate enum_map;
    /// use enum_map::enum_map;
    ///
    /// fn main() {
    ///     let map = enum_map! { false => 3, true => 4 };
    ///     let mut values = map.values();
    ///     assert_eq!(values.next(), Some(&3));
    ///     assert_eq!(values.next(), Some(&4));
    ///     assert_eq!(values.next(), None);
    /// }
    /// ```
    #[inline]
    pub fn values(&self) -> Values<V> {
        Values(self.as_slice().iter())
    }

    /// An iterator visiting all values mutably. The iterator type is `&mut V`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate enum_map;
    /// use enum_map::enum_map;
    ///
    /// fn main() {
    ///     let mut map = enum_map! { _ => 2 };
    ///     for value in map.values_mut() {
    ///         *value += 2;
    ///     }
    ///     assert_eq!(map[false], 4);
    ///     assert_eq!(map[true], 4);
    /// }
    /// ```
    #[inline]
    pub fn values_mut(&mut self) -> ValuesMut<V> {
        ValuesMut(self.as_mut_slice().iter_mut())
    }
}

/// An iterator over the values of `EnumMap`.
///
/// This `struct` is created by the `values` method of `EnumMap`.
/// See its documentation for more.
pub struct Values<'a, V: 'a>(slice::Iter<'a, V>);

impl<'a, V: 'a> Iterator for Values<'a, V> {
    type Item = &'a V;
    #[inline]
    fn next(&mut self) -> Option<&'a V> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a, V: 'a> DoubleEndedIterator for Values<'a, V> {
    #[inline]
    fn next_back(&mut self) -> Option<&'a V> {
        self.0.next_back()
    }
}

impl<'a, V: 'a> ExactSizeIterator for Values<'a, V> {}

impl<'a, V: 'a> FusedIterator for Values<'a, V> {}

/// A mutable iterator over the values of `EnumMap`.
///
/// This `struct` is created by the `values_mut` method of `EnumMap`.
/// See its documentation for more.
pub struct ValuesMut<'a, V: 'a>(slice::IterMut<'a, V>);

impl<'a, V: 'a> Iterator for ValuesMut<'a, V> {
    type Item = &'a mut V;
    #[inline]
    fn next(&mut self) -> Option<&'a mut V> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a, V: 'a> DoubleEndedIterator for ValuesMut<'a, V> {
    #[inline]
    fn next_back(&mut self) -> Option<&'a mut V> {
        self.0.next_back()
    }
}

impl<'a, V: 'a> ExactSizeIterator for ValuesMut<'a, V> {}

impl<'a, V: 'a> FusedIterator for ValuesMut<'a, V> {}
<commit_msg>Implement Clone for Iter<commit_after>use crate::{Enum, EnumMap};
use core::iter::{Enumerate, FusedIterator};
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::ptr;
use core::slice;

/// Immutable enum map iterator
///
/// This struct is created by `iter` method or `into_iter` on a reference
/// to `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Enum)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     assert_eq!(map[Example::A], 3);
///     for (key, &value) in &map {
///         assert_eq!(value, match key {
///             Example::A => 3,
///             _ => 0,
///         });
///     }
/// }
/// ```
#[derive(Debug)]
pub struct Iter<'a, K, V: 'a> {
    _phantom: PhantomData<fn() -> K>,
    iterator: Enumerate<slice::Iter<'a, V>>,
}

impl<'a, K: Enum<V>, V> Clone for Iter<'a, K, V> {
    fn clone(&self) -> Self {
        Iter {
            _phantom: PhantomData,
            iterator: self.iterator.clone(),
        }
    }
}

impl<'a, K: Enum<V>, V> Iterator for Iter<'a, K, V> {
    type Item = (K, &'a V);
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator
            .next()
            .map(|(index, item)| (K::from_usize(index), item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }

    fn fold<B, F>(self, init: B, f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        self.iterator
            .map(|(index, item)| (K::from_usize(index), item))
            .fold(init, f)
    }
}

impl<'a, K: Enum<V>, V> DoubleEndedIterator for Iter<'a, K, V> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator
            .next_back()
            .map(|(index, item)| (K::from_usize(index), item))
    }
}

impl<'a, K: Enum<V>, V> ExactSizeIterator for Iter<'a, K, V> {}

impl<'a, K: Enum<V>, V> FusedIterator for Iter<'a, K, V> {}

impl<'a, K: Enum<V>, V> IntoIterator for &'a EnumMap<K, V> {
    type Item = (K, &'a V);
    type IntoIter = Iter<'a, K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        Iter {
            _phantom: PhantomData,
            iterator: self.as_slice().iter().enumerate(),
        }
    }
}

/// Mutable map iterator
///
/// This struct is created by `iter_mut` method or `into_iter` on a mutable
/// reference to `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Debug, Enum)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     for (_, value) in &mut map {
///         *value += 1;
///     }
///     assert_eq!(map, enum_map! { Example::A => 4, _ => 1 });
/// }
/// ```
#[derive(Debug)]
pub struct IterMut<'a, K, V: 'a> {
    _phantom: PhantomData<fn() -> K>,
    iterator: Enumerate<slice::IterMut<'a, V>>,
}

impl<'a, K: Enum<V>, V> Iterator for IterMut<'a, K, V> {
    type Item = (K, &'a mut V);
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator
            .next()
            .map(|(index, item)| (K::from_usize(index), item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }

    fn fold<B, F>(self, init: B, f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        self.iterator
            .map(|(index, item)| (K::from_usize(index), item))
            .fold(init, f)
    }
}

impl<'a, K: Enum<V>, V> DoubleEndedIterator for IterMut<'a, K, V> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator
            .next_back()
            .map(|(index, item)| (K::from_usize(index), item))
    }
}

impl<'a, K: Enum<V>, V> ExactSizeIterator for IterMut<'a, K, V> {}

impl<'a, K: Enum<V>, V> FusedIterator for IterMut<'a, K, V> {}

impl<'a, K: Enum<V>, V> IntoIterator for &'a mut EnumMap<K, V> {
    type Item = (K, &'a mut V);
    type IntoIter = IterMut<'a, K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IterMut {
            _phantom: PhantomData,
            iterator: self.as_mut_slice().iter_mut().enumerate(),
        }
    }
}

/// A map iterator that moves out of map.
///
/// This struct is created by `into_iter` on `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Debug, Enum)]
/// enum Example {
///     A,
///     B,
/// }
///
/// fn main() {
///     let map = enum_map! { Example::A | Example::B => String::from("123") };
///     for (_, value) in map {
///         assert_eq!(value + "4", "1234");
///     }
/// }
/// ```
pub struct IntoIter<K: Enum<V>, V> {
    map: ManuallyDrop<EnumMap<K, V>>,
    position: usize,
}

impl<K: Enum<V>, V> Iterator for IntoIter<K, V> {
    type Item = (K, V);
    fn next(&mut self) -> Option<(K, V)> {
        let slice = self.map.as_slice();
        if self.position < slice.len() {
            let key = K::from_usize(self.position);
            let result = Some((key, unsafe { ptr::read(&slice[self.position]) }));
            self.position += 1;
            result
        } else {
            None
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let slice = self.map.as_slice();
        let diff = slice.len() - self.position;
        (diff, Some(diff))
    }
}

impl<K: Enum<V>, V> ExactSizeIterator for IntoIter<K, V> {}

impl<K: Enum<V>, V> FusedIterator for IntoIter<K, V> {}

impl<K: Enum<V>, V> Drop for IntoIter<K, V> {
    #[inline]
    fn drop(&mut self) {
        for _item in self {}
    }
}

impl<K: Enum<V>, V> IntoIterator for EnumMap<K, V> {
    type Item = (K, V);
    type IntoIter = IntoIter<K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IntoIter {
            map: ManuallyDrop::new(self),
            position: 0,
        }
    }
}

impl<K: Enum<V>, V> EnumMap<K, V> {
    /// An iterator visiting all values. The iterator type is `&V`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate enum_map;
    /// use enum_map::enum_map;
    ///
    /// fn main() {
    ///     let map = enum_map! { false => 3, true => 4 };
    ///     let mut values = map.values();
    ///     assert_eq!(values.next(), Some(&3));
    ///     assert_eq!(values.next(), Some(&4));
    ///     assert_eq!(values.next(), None);
    /// }
    /// ```
    #[inline]
    pub fn values(&self) -> Values<V> {
        Values(self.as_slice().iter())
    }

    /// An iterator visiting all values mutably. The iterator type is `&mut V`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate enum_map;
    /// use enum_map::enum_map;
    ///
    /// fn main() {
    ///     let mut map = enum_map! { _ => 2 };
    ///     for value in map.values_mut() {
    ///         *value += 2;
    ///     }
    ///     assert_eq!(map[false], 4);
    ///     assert_eq!(map[true], 4);
    /// }
    /// ```
    #[inline]
    pub fn values_mut(&mut self) -> ValuesMut<V> {
        ValuesMut(self.as_mut_slice().iter_mut())
    }
}

/// An iterator over the values of `EnumMap`.
///
/// This `struct` is created by the `values` method of `EnumMap`.
/// See its documentation for more.
pub struct Values<'a, V: 'a>(slice::Iter<'a, V>);

impl<'a, V: 'a> Iterator for Values<'a, V> {
    type Item = &'a V;
    #[inline]
    fn next(&mut self) -> Option<&'a V> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a, V: 'a> DoubleEndedIterator for Values<'a, V> {
    #[inline]
    fn next_back(&mut self) -> Option<&'a V> {
        self.0.next_back()
    }
}

impl<'a, V: 'a> ExactSizeIterator for Values<'a, V> {}

impl<'a, V: 'a> FusedIterator for Values<'a, V> {}

/// A mutable iterator over the values of `EnumMap`.
///
/// This `struct` is created by the `values_mut` method of `EnumMap`.
/// See its documentation for more.
pub struct ValuesMut<'a, V: 'a>(slice::IterMut<'a, V>);

impl<'a, V: 'a> Iterator for ValuesMut<'a, V> {
    type Item = &'a mut V;
    #[inline]
    fn next(&mut self) -> Option<&'a mut V> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a, V: 'a> DoubleEndedIterator for ValuesMut<'a, V> {
    #[inline]
    fn next_back(&mut self) -> Option<&'a mut V> {
        self.0.next_back()
    }
}

impl<'a, V: 'a> ExactSizeIterator for ValuesMut<'a, V> {}

impl<'a, V: 'a> FusedIterator for ValuesMut<'a, V> {}
<|endoftext|>