<commit_before>use std::io;

use actix::fut;
use actix::prelude::*;
use futures::{stream, Future, Stream};
use rand::{thread_rng, Rng, ThreadRng};
use tokio_postgres::{connect, Client, NoTls, Statement};

use crate::models::{Fortune, World};

/// Postgres interface
pub struct PgConnection {
    cl: Option<Client>,
    fortune: Option<Statement>,
    world: Option<Statement>,
    rng: ThreadRng,
}

impl Actor for PgConnection {
    type Context = Context<Self>;
}

impl PgConnection {
    pub fn connect(db_url: &str) -> Addr<PgConnection> {
        let hs = connect(db_url, NoTls);

        PgConnection::create(move |ctx| {
            let act = PgConnection {
                cl: None,
                fortune: None,
                world: None,
                rng: thread_rng(),
            };

            hs.map_err(|_| panic!("can not connect to postgresql"))
                .into_actor(&act)
                .and_then(|(mut cl, conn), act, ctx| {
                    ctx.wait(
                        cl.prepare("SELECT id, message FROM fortune")
                            .map_err(|_| ())
                            .into_actor(act)
                            .and_then(|st, act, _| {
                                act.fortune = Some(st);
                                fut::ok(())
                            }),
                    );
                    ctx.wait(
                        cl.prepare("SELECT id, randomnumber FROM world WHERE id=$1")
                            .map_err(|_| ())
                            .into_actor(act)
                            .and_then(|st, act, _| {
                                act.world = Some(st);
                                fut::ok(())
                            }),
                    );

                    act.cl = Some(cl);
                    Arbiter::spawn(conn.map_err(|e| panic!("{}", e)));
                    fut::ok(())
                })
                .wait(ctx);

            act
        })
    }
}

pub struct RandomWorld;

impl Message for RandomWorld {
    type Result = io::Result<World>;
}

impl Handler<RandomWorld> for PgConnection {
    type Result = ResponseFuture<World, io::Error>;

    fn handle(&mut self, _: RandomWorld, _: &mut Self::Context) -> Self::Result {
        let random_id = self.rng.gen_range::<i32>(1, 10_001);

        Box::new(
            self.cl
                .as_mut()
                .unwrap()
                .query(self.world.as_ref().unwrap(), &[&random_id])
                .into_future()
                .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{:?}", e.0)))
                .and_then(|(row, _)| {
                    let row = row.unwrap();
                    Ok(World {
                        id: row.get(0),
                        randomnumber: row.get(1),
                    })
                }),
        )
    }
}

pub struct RandomWorlds(pub u16);

impl Message for RandomWorlds {
    type Result = io::Result<Vec<World>>;
}

impl Handler<RandomWorlds> for PgConnection {
    type Result = ResponseFuture<Vec<World>, io::Error>;

    fn handle(&mut self, msg: RandomWorlds, _: &mut Self::Context) -> Self::Result {
        let mut worlds = Vec::with_capacity(msg.0 as usize);
        for _ in 0..msg.0 {
            let w_id: i32 = self.rng.gen_range(1, 10_001);
            worlds.push(
                self.cl
                    .as_mut()
                    .unwrap()
                    .query(self.world.as_ref().unwrap(), &[&w_id])
                    .into_future()
                    .map_err(|e| {
                        io::Error::new(io::ErrorKind::Other, format!("{:?}", e.0))
                    })
                    .and_then(|(row, _)| {
                        let row = row.unwrap();
                        Ok(World {
                            id: row.get(0),
                            randomnumber: row.get(1),
                        })
                    }),
            );
        }

        Box::new(stream::futures_unordered(worlds).collect())
    }
}

pub struct UpdateWorld(pub u16);

impl Message for UpdateWorld {
    type Result = io::Result<Vec<World>>;
}

impl Handler<UpdateWorld> for PgConnection {
    type Result = ResponseActFuture<Self, Vec<World>, io::Error>;

    fn handle(&mut self, msg: UpdateWorld, _: &mut Self::Context) -> Self::Result {
        let mut worlds = Vec::with_capacity(msg.0 as usize);
        for _ in 0..msg.0 {
            let id: i32 = self.rng.gen_range(1, 10_001);
            let w_id: i32 = self.rng.gen_range(1, 10_001);
            worlds.push(
                self.cl
                    .as_mut()
                    .unwrap()
                    .query(self.world.as_ref().unwrap(), &[&w_id])
                    .into_future()
                    .map_err(|e| {
                        io::Error::new(io::ErrorKind::Other, format!("{:?}", e.0))
                    })
                    .and_then(move |(row, _)| {
                        let row = row.unwrap();
                        Ok(World {
                            id: row.get(0),
                            randomnumber: id,
                        })
                    }),
            );
        }

        Box::new(
            stream::futures_unordered(worlds)
                .collect()
                .into_actor(self)
                .and_then(move |mut worlds, act, _| {
                    let mut update = String::with_capacity(120 + 6 * msg.0 as usize);
                    update
                        .push_str("UPDATE world SET randomnumber = temp.randomnumber FROM (VALUES ");

                    for w in &worlds {
                        update.push_str(&format!("({}, {}),", w.id, w.randomnumber));
                    }
                    worlds.sort_by_key(|w| w.id);

                    update.pop();
                    update
                        .push_str(" ORDER BY 1) AS temp(id, randomnumber) WHERE temp.id = world.id");

                    act.cl
                        .as_mut()
                        .unwrap()
                        .simple_query(&update)
                        .collect()
                        .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{:?}", e)))
                        .into_actor(act)
                        .and_then(|_, _, _| fut::ok(worlds))
                }),
        )
    }
}

pub struct TellFortune;

impl Message for TellFortune {
    type Result = io::Result<Vec<Fortune>>;
}

impl Handler<TellFortune> for PgConnection {
    type Result = ResponseFuture<Vec<Fortune>, io::Error>;

    fn handle(&mut self, _: TellFortune, _: &mut Self::Context) -> Self::Result {
        let mut items = Vec::with_capacity(16);
        items.push(Fortune {
            id: 0,
            message: "Additional fortune added at request time.".to_string(),
        });

        Box::new(
            self.cl
                .as_mut()
                .unwrap()
                .query(self.fortune.as_ref().unwrap(), &[])
                .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{:?}", e)))
                .fold(items, move |mut items, row| {
                    items.push(Fortune {
                        id: row.get(0),
                        message: row.get(1),
                    });
                    Ok::<_, io::Error>(items)
                })
                .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{:?}", e)))
                .and_then(|mut items| {
                    items.sort_by(|it, next| it.message.cmp(&next.message));
                    Ok(items)
                }),
        )
    }
}
<commit_msg>do not preallocate memory #4672 (#4673)<commit_after>use std::io;

use actix::fut;
use actix::prelude::*;
use futures::{stream, Future, Stream};
use rand::{thread_rng, Rng, ThreadRng};
use tokio_postgres::{connect, Client, NoTls, Statement};

use crate::models::{Fortune, World};

/// Postgres interface
pub struct PgConnection {
    cl: Option<Client>,
    fortune: Option<Statement>,
    world: Option<Statement>,
    rng: ThreadRng,
}

impl Actor for PgConnection {
    type Context = Context<Self>;
}

impl PgConnection {
    pub fn connect(db_url: &str) -> Addr<PgConnection> {
        let hs = connect(db_url, NoTls);

        PgConnection::create(move |ctx| {
            let act = PgConnection {
                cl: None,
                fortune: None,
                world: None,
                rng: thread_rng(),
            };

            hs.map_err(|_| panic!("can not connect to postgresql"))
                .into_actor(&act)
                .and_then(|(mut cl, conn), act, ctx| {
                    ctx.wait(
                        cl.prepare("SELECT id, message FROM fortune")
                            .map_err(|_| ())
                            .into_actor(act)
                            .and_then(|st, act, _| {
                                act.fortune = Some(st);
                                fut::ok(())
                            }),
                    );
                    ctx.wait(
                        cl.prepare("SELECT id, randomnumber FROM world WHERE id=$1")
                            .map_err(|_| ())
                            .into_actor(act)
                            .and_then(|st, act, _| {
                                act.world = Some(st);
                                fut::ok(())
                            }),
                    );

                    act.cl = Some(cl);
                    Arbiter::spawn(conn.map_err(|e| panic!("{}", e)));
                    fut::ok(())
                })
                .wait(ctx);

            act
        })
    }
}

pub struct RandomWorld;

impl Message for RandomWorld {
    type Result = io::Result<World>;
}

impl Handler<RandomWorld> for PgConnection {
    type Result = ResponseFuture<World, io::Error>;

    fn handle(&mut self, _: RandomWorld, _: &mut Self::Context) -> Self::Result {
        let random_id = self.rng.gen_range::<i32>(1, 10_001);

        Box::new(
            self.cl
                .as_mut()
                .unwrap()
                .query(self.world.as_ref().unwrap(), &[&random_id])
                .into_future()
                .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{:?}", e.0)))
                .and_then(|(row, _)| {
                    let row = row.unwrap();
                    Ok(World {
                        id: row.get(0),
                        randomnumber: row.get(1),
                    })
                }),
        )
    }
}

pub struct RandomWorlds(pub u16);

impl Message for RandomWorlds {
    type Result = io::Result<Vec<World>>;
}

impl Handler<RandomWorlds> for PgConnection {
    type Result = ResponseFuture<Vec<World>, io::Error>;

    fn handle(&mut self, msg: RandomWorlds, _: &mut Self::Context) -> Self::Result {
        let mut worlds = Vec::with_capacity(msg.0 as usize);
        for _ in 0..msg.0 {
            let w_id: i32 = self.rng.gen_range(1, 10_001);
            worlds.push(
                self.cl
                    .as_mut()
                    .unwrap()
                    .query(self.world.as_ref().unwrap(), &[&w_id])
                    .into_future()
                    .map_err(|e| {
                        io::Error::new(io::ErrorKind::Other, format!("{:?}", e.0))
                    })
                    .and_then(|(row, _)| {
                        let row = row.unwrap();
                        Ok(World {
                            id: row.get(0),
                            randomnumber: row.get(1),
                        })
                    }),
            );
        }

        Box::new(stream::futures_unordered(worlds).collect())
    }
}

pub struct UpdateWorld(pub u16);

impl Message for UpdateWorld {
    type Result = io::Result<Vec<World>>;
}

impl Handler<UpdateWorld> for PgConnection {
    type Result = ResponseActFuture<Self, Vec<World>, io::Error>;

    fn handle(&mut self, msg: UpdateWorld, _: &mut Self::Context) -> Self::Result {
        let mut worlds = Vec::with_capacity(msg.0 as usize);
        for _ in 0..msg.0 {
            let id: i32 = self.rng.gen_range(1, 10_001);
            let w_id: i32 = self.rng.gen_range(1, 10_001);
            worlds.push(
                self.cl
                    .as_mut()
                    .unwrap()
                    .query(self.world.as_ref().unwrap(), &[&w_id])
                    .into_future()
                    .map_err(|e| {
                        io::Error::new(io::ErrorKind::Other, format!("{:?}", e.0))
                    })
                    .and_then(move |(row, _)| {
                        let row = row.unwrap();
                        Ok(World {
                            id: row.get(0),
                            randomnumber: id,
                        })
                    }),
            );
        }

        Box::new(
            stream::futures_unordered(worlds)
                .collect()
                .into_actor(self)
                .and_then(move |mut worlds, act, _| {
                    let mut update = String::with_capacity(120 + 6 * msg.0 as usize);
                    update
                        .push_str("UPDATE world SET randomnumber = temp.randomnumber FROM (VALUES ");

                    for w in &worlds {
                        update.push_str(&format!("({}, {}),", w.id, w.randomnumber));
                    }
                    worlds.sort_by_key(|w| w.id);

                    update.pop();
                    update
                        .push_str(" ORDER BY 1) AS temp(id, randomnumber) WHERE temp.id = world.id");

                    act.cl
                        .as_mut()
                        .unwrap()
                        .simple_query(&update)
                        .collect()
                        .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{:?}", e)))
                        .into_actor(act)
                        .and_then(|_, _, _| fut::ok(worlds))
                }),
        )
    }
}

pub struct TellFortune;

impl Message for TellFortune {
    type Result = io::Result<Vec<Fortune>>;
}

impl Handler<TellFortune> for PgConnection {
    type Result = ResponseFuture<Vec<Fortune>, io::Error>;

    fn handle(&mut self, _: TellFortune, _: &mut Self::Context) -> Self::Result {
        let items = vec![Fortune {
            id: 0,
            message: "Additional fortune added at request time.".to_string(),
        }];

        Box::new(
            self.cl
                .as_mut()
                .unwrap()
                .query(self.fortune.as_ref().unwrap(), &[])
                .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{:?}", e)))
                .fold(items, move |mut items, row| {
                    items.push(Fortune {
                        id: row.get(0),
                        message: row.get(1),
                    });
                    Ok::<_, io::Error>(items)
                })
                .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{:?}", e)))
                .and_then(|mut items| {
                    items.sort_by(|it, next| it.message.cmp(&next.message));
                    Ok(items)
                }),
        )
    }
}
<|endoftext|>


<commit_before><commit_msg>remove errant file<commit_after><|endoftext|>


<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use std::mem;
use std::default::Default;

use token::Token;
use token::Data;
use logger::Logger;

pub fn traverse_token<F1, F2, R>(token: &Token, f: &F1, add: &F2) -> R
    where F1: Fn(&str) -> R,
          R: Default,
          F2: Fn(R, R) -> R
{
    match token {
        &Token::Str(ref s) => f(s),

        &Token::Rule
            | &Token::SoftBreak
            | &Token::HardBreak
            => f("\n"),

        &Token::Image(..)
            | &Token::StandaloneImage(..)
            | &Token::Footnote(..)
            | &Token::Table(..)
            | &Token::TableHead(..)
            | &Token::TableRow(..)
            | &Token::TableCell(..)
            => f(""),

        _ => traverse_vec(token.inner().unwrap(), f, add),
    }
}

/// Traverse a vector of tokens
#[doc(hidden)]
pub fn traverse_vec<F1, F2, R>(tokens: &[Token], f:&F1, add: &F2) -> R
    where F1: Fn(&str) -> R,
          F2: Fn(R, R) -> R,
          R: Default
{
    tokens.iter()
        .map(|t| traverse_token(t, f, add))
        .fold(R::default(), |r1, r2| add(r1, r2))
}

/// Returns the content of an AST as raw text, without any formatting
/// Useful for tools like grammar checks
pub fn view_as_text(tokens: &[Token]) -> String {
        traverse_vec(tokens,
                     &|s| s.to_owned(),
                     &|s1, s2| s1 + &s2)
    }

pub fn count_length(tokens: &[Token]) -> usize {
    traverse_vec(tokens,
                 &|s| s.chars().count(),
                 &|s1, s2| s1 + s2)
}

/// Insert an annotation at begin and end pos begin+len in the text_view
#[doc(hidden)]
pub fn insert_annotation(tokens: &mut Vec<Token>, annotation: &Data, pos: usize, length: usize) -> Option<usize> {
    let mut pos = pos;
    let mut found_left = None;
    let mut found_right = None;
    for i in 0..tokens.len() {
        let recurse  = match tokens[i] {
            Token::Str(ref s) => {
                let len = s.chars().count();
                if pos < len || (pos == len && found_left.is_some()) {
                    // We found the first element already, so now it's the right
                    if found_left.is_some() {
                        found_right = Some((i, pos));
                        break;
                    }
                    found_left = Some((i, pos));
                    pos += length;
                    if pos <= len {
                        found_right = Some((i, pos));
                        break;
                    }
                }
                pos = pos - len;
                false
            },

            Token::Rule
                | Token::SoftBreak
                | Token::HardBreak
                => {
                    if pos < 1 {
                        if found_left.is_some() {
                            found_right = Some((i, pos));
                            break;
                        }
                        found_left = Some((i, pos));
                        pos += length;
                        if pos <= 1 {
                            found_right = Some((i, pos));
                            break;
                        }
                    }
                    pos -= 1;
                    false
                },

            _ => {
                if let Some(ref inner) = tokens[i].inner() {
                    let len = count_length(inner);
                    // Only recurse if the two is in this subtree
                    if pos < len {
                        if found_left.is_none() {
                            true
                        } else {
                            Logger::display_warning("ignored annotation as it wasn't compatible with the Markdown structure");
                            return None;
                        }
                    } else {
                        pos -= len;
                        false
                    }
                } else {
                    false
                }

            },
        };

        // Moved out of the match 'thanks' to borrowcheck
        if recurse {
            if let Some(ref mut inner) = tokens[i].inner_mut() {
                if let Some(new_pos) = insert_annotation(inner, annotation, pos, length) {
                    pos = new_pos;
                } else {
                    return None;
                }
            }
        }
    }

    if let (Some((i, pos_left)), Some((j, pos_right))) = (found_left, found_right) {
        let pos_right = pos_right;
        let mut vec = vec!();

        // Beginning token: keep the left part in the str, put the right one in our vec
        if !tokens[i].is_str() || pos_left == 0 {
            // do nothing
        } else {
            let old_token = mem::replace(&mut tokens[i], Token::Str(String::new()));
            if let Token::Str(old_str) = old_token {
                let mut chars_left:Vec<char> = old_str.chars().collect();
                let mut chars_right = chars_left.split_off(pos_left);

                let str_left:String = chars_left.into_iter().collect();
                tokens[i] = Token::Str(str_left);

                if i == j { // i and j are in same str, so split again
                    if length != chars_right.len() {
                        let inline_token = chars_right.split_off(length);
                        let inline_token = Token::Str(inline_token.into_iter().collect());
                        if pos_left == 0 {
                            tokens.insert(i, inline_token)
                        } else if i == tokens.len() {
                            tokens.push(inline_token);
                        } else {
                            tokens.insert(i+1, inline_token);
                        }
                    }
                    let annot = Token::Annotation(annotation.clone(), vec!(Token::Str(chars_right.into_iter().collect())));
                    if pos_left == 0 {
                        tokens.insert(i, annot)
                    } else if i == tokens.len() {
                        tokens.push(annot);
                    } else {
                        tokens.insert(i+1, annot);
                    }
                    return None;
                }

                let str_right:String = chars_right.into_iter().collect();
                vec.push(Token::Str(str_right));
            } else {
                unreachable!();
            }
        }

        // Middle tokens: remove them entirely and put them in our vec
        for _ in i+1..j {
            vec.push(tokens.remove(i+1));
        }

        // End token: keep the right part in the str, put the left one in our vec
        // j is now i + 1 because all tokens in between have been removed
        // unless j was equal to i to begin with
        let j = if i == j || i >= tokens.len() - 1 {
            i
        } else {
            i + 1
        };

        if !tokens[j].is_str() {
            // do nothing
        } else {
            let count = if let Token::Str(ref s) = tokens[j] {
                s.chars().count()
            } else {
                unreachable!()
            };
            if count != pos_right {
                let old_token = mem::replace(&mut tokens[j], Token::Rule);
                if let Token::Str(old_str) = old_token {
                    let mut chars_left:Vec<char> = old_str.chars().collect();
                    let chars_right = chars_left.split_off(pos_right);
                    let str_left:String = chars_left.into_iter().collect();
                    let str_right:String = chars_right.into_iter().collect();
                    tokens[j] = Token::Str(str_right);
                    // todo: if only one token, maybe concat the strings
                    vec.push(Token::Str(str_left));
                } else {
                    unreachable!();
                }
            }
        }
        let new_token = Token::Annotation(annotation.clone(), vec);
        if pos_left == 0 {
            tokens.insert(i, new_token);
        }  else if i >= tokens.len() - 1 {
            tokens.push(new_token);
        } else {
            tokens.insert(i+1, new_token);
        }
        return None;
    } else {
        if found_left.is_none() && found_right.is_none() {
            return Some(pos);
        } else {
            Logger::display_warning("ignored annotation as it wasn't compatible with the Markdown structure");
            return None;
        }
    }
}

#[test]
fn test_text_view() {
    let ast = vec!(Token::Str("123".to_owned()),
                   Token::Emphasis(vec!(Token::Str("456".to_owned()))),
                   Token::Str("789".to_owned()));
    assert_eq!(view_as_text(&ast), "123456789");
}

// #[test]
// fn test_text_insert() {
//     let mut ast = vec!(Token::Str("123".to_owned()),
//                        Token::Emphasis(vec!(Token::Str("456".to_owned()))),
//                        Token::Str("789".to_owned()));
//     insert_at(&mut ast, "!!!", 5);
//     let expected = vec!(Token::Str("123".to_owned()),
//                         Token::Emphasis(vec!(Token::Str("45".to_owned()),
//                                              Token::Comment("!!!".to_owned()),
//                                              Token::Str("6".to_owned()))),
//                         Token::Str("789".to_owned()));
//     assert_eq!(expected, ast);
// }
<commit_msg>Display the annotation that couldn't be inserted<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use std::mem;
use std::default::Default;

use token::Token;
use token::Data;
use logger::Logger;

pub fn traverse_token<F1, F2, R>(token: &Token, f: &F1, add: &F2) -> R
    where F1: Fn(&str) -> R,
          R: Default,
          F2: Fn(R, R) -> R
{
    match token {
        &Token::Str(ref s) => f(s),

        &Token::Rule
            | &Token::SoftBreak
            | &Token::HardBreak
            => f("\n"),

        &Token::Image(..)
            | &Token::StandaloneImage(..)
            | &Token::Footnote(..)
            | &Token::Table(..)
            | &Token::TableHead(..)
            | &Token::TableRow(..)
            | &Token::TableCell(..)
            => f(""),

        _ => traverse_vec(token.inner().unwrap(), f, add),
    }
}

/// Traverse a vector of tokens
#[doc(hidden)]
pub fn traverse_vec<F1, F2, R>(tokens: &[Token], f:&F1, add: &F2) -> R
    where F1: Fn(&str) -> R,
          F2: Fn(R, R) -> R,
          R: Default
{
    tokens.iter()
        .map(|t| traverse_token(t, f, add))
        .fold(R::default(), |r1, r2| add(r1, r2))
}

/// Returns the content of an AST as raw text, without any formatting
/// Useful for tools like grammar checks
pub fn view_as_text(tokens: &[Token]) -> String {
        traverse_vec(tokens,
                     &|s| s.to_owned(),
                     &|s1, s2| s1 + &s2)
    }

pub fn count_length(tokens: &[Token]) -> usize {
    traverse_vec(tokens,
                 &|s| s.chars().count(),
                 &|s1, s2| s1 + s2)
}

/// Insert an annotation at begin and end pos begin+len in the text_view
#[doc(hidden)]
pub fn insert_annotation(tokens: &mut Vec<Token>, annotation: &Data, pos: usize, length: usize) -> Option<usize> {
    let mut pos = pos;
    let mut found_left = None;
    let mut found_right = None;
    for i in 0..tokens.len() {
        let recurse  = match tokens[i] {
            Token::Str(ref s) => {
                let len = s.chars().count();
                if pos < len || (pos == len && found_left.is_some()) {
                    // We found the first element already, so now it's the right
                    if found_left.is_some() {
                        found_right = Some((i, pos));
                        break;
                    }
                    found_left = Some((i, pos));
                    pos += length;
                    if pos <= len {
                        found_right = Some((i, pos));
                        break;
                    }
                }
                pos = pos - len;
                false
            },

            Token::Rule
                | Token::SoftBreak
                | Token::HardBreak
                => {
                    if pos < 1 {
                        if found_left.is_some() {
                            found_right = Some((i, pos));
                            break;
                        }
                        found_left = Some((i, pos));
                        pos += length;
                        if pos <= 1 {
                            found_right = Some((i, pos));
                            break;
                        }
                    }
                    pos -= 1;
                    false
                },

            _ => {
                if let Some(ref inner) = tokens[i].inner() {
                    let len = count_length(inner);
                    // Only recurse if the two is in this subtree
                    if pos < len {
                        if found_left.is_none() {
                            true
                        } else {
                            Logger::display_warning(format!("ignored annotation {:?} as it wasn't compatible with the Markdown structure", annotation));
                            return None;
                        }
                    } else {
                        pos -= len;
                        false
                    }
                } else {
                    false
                }

            },
        };

        // Moved out of the match 'thanks' to borrowcheck
        if recurse {
            if let Some(ref mut inner) = tokens[i].inner_mut() {
                if let Some(new_pos) = insert_annotation(inner, annotation, pos, length) {
                    pos = new_pos;
                } else {
                    return None;
                }
            }
        }
    }

    if let (Some((i, pos_left)), Some((j, pos_right))) = (found_left, found_right) {
        let pos_right = pos_right;
        let mut vec = vec!();

        // Beginning token: keep the left part in the str, put the right one in our vec
        if !tokens[i].is_str() || pos_left == 0 {
            // do nothing
        } else {
            let old_token = mem::replace(&mut tokens[i], Token::Str(String::new()));
            if let Token::Str(old_str) = old_token {
                let mut chars_left:Vec<char> = old_str.chars().collect();
                let mut chars_right = chars_left.split_off(pos_left);

                let str_left:String = chars_left.into_iter().collect();
                tokens[i] = Token::Str(str_left);

                if i == j { // i and j are in same str, so split again
                    if length != chars_right.len() {
                        let inline_token = chars_right.split_off(length);
                        let inline_token = Token::Str(inline_token.into_iter().collect());
                        if pos_left == 0 {
                            tokens.insert(i, inline_token)
                        } else if i == tokens.len() {
                            tokens.push(inline_token);
                        } else {
                            tokens.insert(i+1, inline_token);
                        }
                    }
                    let annot = Token::Annotation(annotation.clone(), vec!(Token::Str(chars_right.into_iter().collect())));
                    if pos_left == 0 {
                        tokens.insert(i, annot)
                    } else if i == tokens.len() {
                        tokens.push(annot);
                    } else {
                        tokens.insert(i+1, annot);
                    }
                    return None;
                }

                let str_right:String = chars_right.into_iter().collect();
                vec.push(Token::Str(str_right));
            } else {
                unreachable!();
            }
        }

        // Middle tokens: remove them entirely and put them in our vec
        for _ in i+1..j {
            vec.push(tokens.remove(i+1));
        }

        // End token: keep the right part in the str, put the left one in our vec
        // j is now i + 1 because all tokens in between have been removed
        // unless j was equal to i to begin with
        let j = if i == j || i >= tokens.len() - 1 {
            i
        } else {
            i + 1
        };

        if !tokens[j].is_str() {
            // do nothing
        } else {
            let count = if let Token::Str(ref s) = tokens[j] {
                s.chars().count()
            } else {
                unreachable!()
            };
            if count != pos_right {
                let old_token = mem::replace(&mut tokens[j], Token::Rule);
                if let Token::Str(old_str) = old_token {
                    let mut chars_left:Vec<char> = old_str.chars().collect();
                    let chars_right = chars_left.split_off(pos_right);
                    let str_left:String = chars_left.into_iter().collect();
                    let str_right:String = chars_right.into_iter().collect();
                    tokens[j] = Token::Str(str_right);
                    // todo: if only one token, maybe concat the strings
                    vec.push(Token::Str(str_left));
                } else {
                    unreachable!();
                }
            }
        }
        let new_token = Token::Annotation(annotation.clone(), vec);
        if pos_left == 0 {
            tokens.insert(i, new_token);
        }  else if i >= tokens.len() - 1 {
            tokens.push(new_token);
        } else {
            tokens.insert(i+1, new_token);
        }
        return None;
    } else {
        if found_left.is_none() && found_right.is_none() {
            return Some(pos);
        } else {
            Logger::display_warning(format!("ignored annotation {:?} as it wasn't compatible with the Markdown structure", annotation));
            return None;
        }
    }
}

#[test]
fn test_text_view() {
    let ast = vec!(Token::Str("123".to_owned()),
                   Token::Emphasis(vec!(Token::Str("456".to_owned()))),
                   Token::Str("789".to_owned()));
    assert_eq!(view_as_text(&ast), "123456789");
}

// #[test]
// fn test_text_insert() {
//     let mut ast = vec!(Token::Str("123".to_owned()),
//                        Token::Emphasis(vec!(Token::Str("456".to_owned()))),
//                        Token::Str("789".to_owned()));
//     insert_at(&mut ast, "!!!", 5);
//     let expected = vec!(Token::Str("123".to_owned()),
//                         Token::Emphasis(vec!(Token::Str("45".to_owned()),
//                                              Token::Comment("!!!".to_owned()),
//                                              Token::Str("6".to_owned()))),
//                         Token::Str("789".to_owned()));
//     assert_eq!(expected, ast);
// }
<|endoftext|>


<commit_before>extern crate "rust-hl-lua" as lua;

#[test]
fn readwrite() {
    #[deriving(Clone)]
    struct Foo;
    impl<L: lua::HasLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }
    impl<L: lua::HasLua> lua::CopyRead<L> for Foo {
        fn read_from_lua(lua: &mut L, index: i32) -> Option<Foo> {
            lua::userdata::read_copy_userdata(lua, index)
        }
    }

    let mut lua = lua::Lua::new();

    lua.set("a", Foo);
    let _: Foo = lua.get("a").unwrap();
}

#[test]
fn destructor_called() {
    use std::sync::{Arc, Mutex};

    let called = Arc::new(Mutex::new(false));

    struct Foo {
        called: Arc<Mutex<bool>>
    }

    impl Drop for Foo {
        fn drop(&mut self) {
            let mut called = self.called.lock();
            (*called) = true;
        }
    }

    impl<L: lua::HasLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }

    {
        let mut lua = lua::Lua::new();
        lua.set("a", Foo{called: called.clone()});
    }

    let locked = called.lock();
    assert!(*locked);
}

#[test]
fn type_check() {
    #[deriving(Clone)]
    struct Foo;
    impl<L: lua::HasLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }
    impl<L: lua::HasLua> lua::CopyRead<L> for Foo {
        fn read_from_lua(lua: &mut L, index: i32) -> Option<Foo> {
            lua::userdata::read_copy_userdata(lua, index)
        }
    }

    #[deriving(Clone)]
    struct Bar;
    impl<L: lua::HasLua> lua::Push<L> for Bar {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }
    impl<L: lua::HasLua> lua::CopyRead<L> for Bar {
        fn read_from_lua(lua: &mut L, index: i32) -> Option<Bar> {
            lua::userdata::read_copy_userdata(lua, index)
        }
    }

    let mut lua = lua::Lua::new();

    lua.set("a", Foo);

    let x: Option<Bar> = lua.get("a");
    assert!(x.is_none())
}

#[test]
fn metatables() {
    #[deriving(Clone)]
    struct Foo;
    impl<L: lua::HasLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |table| {
                table.set("__index".to_string(), vec!(
                    ("test".to_string(), || 5i)
                ));
            })
        }
    }

    let mut lua = lua::Lua::new();

    lua.set("a", Foo);

    let x: int = lua.execute("return a.test()").unwrap();
    assert_eq!(x, 5);
}
<commit_msg>Fix for Mutex::lock() returning a Result<commit_after>extern crate "rust-hl-lua" as lua;

#[test]
fn readwrite() {
    #[deriving(Clone)]
    struct Foo;
    impl<L: lua::HasLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }
    impl<L: lua::HasLua> lua::CopyRead<L> for Foo {
        fn read_from_lua(lua: &mut L, index: i32) -> Option<Foo> {
            lua::userdata::read_copy_userdata(lua, index)
        }
    }

    let mut lua = lua::Lua::new();

    lua.set("a", Foo);
    let _: Foo = lua.get("a").unwrap();
}

#[test]
fn destructor_called() {
    use std::sync::{Arc, Mutex};

    let called = Arc::new(Mutex::new(false));

    struct Foo {
        called: Arc<Mutex<bool>>
    }

    impl Drop for Foo {
        fn drop(&mut self) {
            let mut called = self.called.lock().unwrap();
            (*called) = true;
        }
    }

    impl<L: lua::HasLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }

    {
        let mut lua = lua::Lua::new();
        lua.set("a", Foo{called: called.clone()});
    }

    let locked = called.lock().unwrap();
    assert!(*locked);
}

#[test]
fn type_check() {
    #[deriving(Clone)]
    struct Foo;
    impl<L: lua::HasLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }
    impl<L: lua::HasLua> lua::CopyRead<L> for Foo {
        fn read_from_lua(lua: &mut L, index: i32) -> Option<Foo> {
            lua::userdata::read_copy_userdata(lua, index)
        }
    }

    #[deriving(Clone)]
    struct Bar;
    impl<L: lua::HasLua> lua::Push<L> for Bar {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |_|{})
        }
    }
    impl<L: lua::HasLua> lua::CopyRead<L> for Bar {
        fn read_from_lua(lua: &mut L, index: i32) -> Option<Bar> {
            lua::userdata::read_copy_userdata(lua, index)
        }
    }

    let mut lua = lua::Lua::new();

    lua.set("a", Foo);

    let x: Option<Bar> = lua.get("a");
    assert!(x.is_none())
}

#[test]
fn metatables() {
    #[deriving(Clone)]
    struct Foo;
    impl<L: lua::HasLua> lua::Push<L> for Foo {
        fn push_to_lua(self, lua: &mut L) -> uint {
            lua::userdata::push_userdata(self, lua, |table| {
                table.set("__index".to_string(), vec!(
                    ("test".to_string(), || 5i)
                ));
            })
        }
    }

    let mut lua = lua::Lua::new();

    lua.set("a", Foo);

    let x: int = lua.execute("return a.test()").unwrap();
    assert_eq!(x, 5);
}
<|endoftext|>


<commit_before>pub fn encode(text: &str) -> String {

    let mut count = 0;
    let mut result = String::new();
    let mut iter = text.chars().peekable();

    while let Some(c) = iter.next() {
        count += 1;

        if iter.peek() != Some(&c) {
            if count > 1 {
                result.push_str(&count.to_string());
            }

            result.push(c);

            count = 0;
        }
    }

    result
}

pub fn decode(text: &str) -> String {
    let mut count = 0;
    let mut result = String::new();

    for c in text.chars() {
        if let Some(v) = c.to_digit(10) {
            count = count * 10 + v as usize;

            continue;
        }

        if count < 2 {
            result.push(c);
        } else {
            let s = std::iter::repeat(c).take(count).collect::<String>();

            result.push_str(&s);
        }

        count = 0;
    }

    result
}
<commit_msg>Remove blank line<commit_after>pub fn encode(text: &str) -> String {
    let mut count = 0;
    let mut result = String::new();
    let mut iter = text.chars().peekable();

    while let Some(c) = iter.next() {
        count += 1;

        if iter.peek() != Some(&c) {
            if count > 1 {
                result.push_str(&count.to_string());
            }

            result.push(c);

            count = 0;
        }
    }

    result
}

pub fn decode(text: &str) -> String {
    let mut count = 0;
    let mut result = String::new();

    for c in text.chars() {
        if let Some(v) = c.to_digit(10) {
            count = count * 10 + v as usize;

            continue;
        }

        if count < 2 {
            result.push(c);
        } else {
            let s = std::iter::repeat(c).take(count).collect::<String>();

            result.push_str(&s);
        }

        count = 0;
    }

    result
}
<|endoftext|>


<commit_before>//! [GET /_matrix/client/r0/login](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-login)

use std::borrow::Cow;

use ruma_api::ruma_api;
use ruma_identifiers::MxcUri;
use ruma_serde::{JsonObject, StringEnum};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::Value as JsonValue;

use crate::PrivOwnedStr;

ruma_api! {
    metadata: {
        description: "Gets the homeserver's supported login types to authenticate users. Clients should pick one of these and supply it as the type when logging in.",
        method: GET,
        name: "get_login_types",
        path: "/_matrix/client/r0/login",
        rate_limited: true,
        authentication: None,
    }

    #[derive(Default)]
    request: {}

    response: {
        /// The homeserver's supported login types.
        pub flows: Vec<LoginType>,
    }

    error: crate::Error
}

impl Request {
    /// Creates an empty `Request`.
    pub fn new() -> Self {
        Self {}
    }
}

impl Response {
    /// Creates a new `Response` with the given login types.
    pub fn new(flows: Vec<LoginType>) -> Self {
        Self { flows }
    }
}

/// An authentication mechanism.
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(untagged)]
pub enum LoginType {
    /// A password is supplied to authenticate.
    Password(PasswordLoginType),

    /// Token-based login.
    Token(TokenLoginType),

    /// SSO-based login.
    Sso(SsoLoginType),

    /// Custom login type.
    #[doc(hidden)]
    _Custom(CustomLoginType),
}

impl LoginType {
    /// Creates a new `LoginType` with the given `login_type` string and data.
    ///
    /// Prefer to use the public variants of `LoginType` where possible; this constructor is meant
    /// be used for unsupported login types only and does not allow setting arbitrary data for
    /// supported ones.
    pub fn new(login_type: &str, data: JsonObject) -> serde_json::Result<Self> {
        fn from_json_object<T: DeserializeOwned>(obj: JsonObject) -> serde_json::Result<T> {
            serde_json::from_value(JsonValue::Object(obj))
        }

        Ok(match login_type {
            "m.login.password" => Self::Password(from_json_object(data)?),
            "m.login.token" => Self::Token(from_json_object(data)?),
            "m.login.sso" => Self::Sso(from_json_object(data)?),
            _ => Self::_Custom(CustomLoginType { type_: login_type.to_owned(), data }),
        })
    }

    /// Returns a reference to the `login_type` string.
    pub fn login_type(&self) -> &str {
        match self {
            Self::Password(_) => "m.login.password",
            Self::Token(_) => "m.login.token",
            Self::Sso(_) => "m.login.sso",
            Self::_Custom(c) => &c.type_,
        }
    }

    /// Returns the associated data.
    ///
    /// Prefer to use the public variants of `LoginType` where possible; this method is meant to
    /// be used for unsupported login types only.
    pub fn data(&self) -> Cow<'_, JsonObject> {
        fn serialize<T: Serialize>(obj: &T) -> JsonObject {
            match serde_json::to_value(obj).expect("login type serialization to succeed") {
                JsonValue::Object(obj) => obj,
                _ => panic!("all login types must serialize to objects"),
            }
        }

        match self {
            Self::Password(d) => Cow::Owned(serialize(d)),
            Self::Token(d) => Cow::Owned(serialize(d)),
            Self::Sso(d) => Cow::Owned(serialize(d)),
            Self::_Custom(c) => Cow::Borrowed(&c.data),
        }
    }
}

/// The payload for password login.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type", rename = "m.login.password")]
pub struct PasswordLoginType {}

impl PasswordLoginType {
    /// Creates a new `PasswordLoginType`.
    pub fn new() -> Self {
        Self {}
    }
}

/// The payload for token-based login.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type", rename = "m.login.token")]
pub struct TokenLoginType {}

impl TokenLoginType {
    /// Creates a new `PasswordLoginType`.
    pub fn new() -> Self {
        Self {}
    }
}

/// The payload for SSO login.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type", rename = "m.login.sso")]
pub struct SsoLoginType {
    /// The identity provider choices.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub identity_providers: Vec<IdentityProvider>,
}

impl SsoLoginType {
    /// Creates a new `PasswordLoginType`.
    pub fn new() -> Self {
        Self::default()
    }
}

/// An SSO login identity provider.
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct IdentityProvider {
    /// The ID of the provider.
    pub id: String,

    /// The display name of the provider.
    pub name: String,

    /// The icon for the provider.
    pub icon: Option<Box<MxcUri>>,

    /// The brand identifier for the provider.
    pub brand: Option<IdentityProviderBrand>,
}

impl IdentityProvider {
    /// Creates an `IdentityProvider` with the given `id` and `name`.
    pub fn new(id: String, name: String) -> Self {
        Self { id, name, icon: None, brand: None }
    }
}

/// An SSO login identity provider brand identifier.
///
/// The predefined ones can be found in the matrix-doc repo in a [separate document][matrix-doc].
/// To use a custom brand string, simply use `IdentityProviderBrand::from("custom-brand")` or
/// `"custom-brand".into()` (if the type is known from the surrounding context).
///
/// [matrix-doc]: https://github.com/matrix-org/matrix-doc/blob/v1.1/informal/idp-brands.md
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum IdentityProviderBrand {
    /// The [Apple] brand.
    ///
    /// [Apple]: https://developer.apple.com/design/human-interface-guidelines/sign-in-with-apple/overview/buttons/
    #[ruma_enum(rename = "apple")]
    Apple,

    /// The [Facebook](https://developers.facebook.com/docs/facebook-login/web/login-button/) brand.
    #[ruma_enum(rename = "facebook")]
    Facebook,

    /// The [GitHub](https://github.com/logos) brand.
    #[ruma_enum(rename = "github")]
    GitHub,

    /// The [GitLab](https://about.gitlab.com/press/press-kit/) brand.
    #[ruma_enum(rename = "gitlab")]
    GitLab,

    /// The [Google](https://developers.google.com/identity/branding-guidelines) brand.
    #[ruma_enum(rename = "google")]
    Google,

    /// The [Twitter] brand.
    ///
    /// [Twitter]: https://developer.twitter.com/en/docs/authentication/guides/log-in-with-twitter#tab1
    #[ruma_enum(rename = "twitter")]
    Twitter,

    /// A custom brand.
    #[doc(hidden)]
    _Custom(PrivOwnedStr),
}

/// A custom login payload.
#[doc(hidden)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[allow(clippy::exhaustive_structs)]
pub struct CustomLoginType {
    /// A custom type
    ///
    /// This field is named `type_` instead of `type` because the latter is a reserved
    /// keyword in Rust.
    #[serde(rename = "type")]
    pub type_: String,

    /// Remaining type content
    #[serde(flatten)]
    pub data: JsonObject,
}

mod login_type_serde;

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    use serde::{Deserialize, Serialize};
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::{
        CustomLoginType, IdentityProvider, IdentityProviderBrand, LoginType, PasswordLoginType,
        SsoLoginType, TokenLoginType,
    };

    #[derive(Debug, Deserialize, Serialize)]
    struct Wrapper {
        pub flows: Vec<LoginType>,
    }

    #[test]
    fn deserialize_password_login_type() {
        assert_matches!(
            from_json_value::<Wrapper>(json!({
                "flows": [
                    { "type": "m.login.password" }
                ],
            })),
            Ok(Wrapper { flows })
            if flows.len() == 1
                && matches!(flows[0], LoginType::Password(PasswordLoginType {}))
        );
    }

    #[test]
    fn deserialize_custom_login_type() {
        assert_matches!(
            from_json_value::<Wrapper>(json!({
                "flows": [
                    {
                        "type": "io.ruma.custom",
                        "color": "green",
                    }
                ],
            })),
            Ok(Wrapper { flows })
            if flows.len() == 1
                && matches!(
                    &flows[0],
                    LoginType::_Custom(CustomLoginType { type_, data })
                        if type_ == "io.ruma.custom"
                        && data == json!({ "color": "green" }).as_object().unwrap()
                )
        );
    }

    #[test]
    fn deserialize_sso_login_type() {
        let mut wrapper = from_json_value::<Wrapper>(json!({
            "flows": [
                {
                    "type": "m.login.sso",
                    "identity_providers": [
                        {
                            "id": "oidc-gitlab",
                            "name": "GitLab",
                            "icon": "mxc://localhost/gitlab-icon",
                            "brand": "org.matrix.gitlab"
                        },
                        {
                            "id": "custom",
                            "name": "Custom",
                        }
                    ]
                }
            ],
        }))
        .unwrap();

        let flow = wrapper.flows.pop();
        assert_matches!(wrapper.flows.as_slice(), []);

        let mut identity_providers = match flow {
            Some(LoginType::Sso(SsoLoginType { identity_providers })) => identity_providers,
            _ => panic!("unexpected enum variant: {:?}", flow),
        };

        let provider = identity_providers.pop();
        assert_matches!(
            provider,
            Some(IdentityProvider {
                id,
                name,
                icon: None,
                brand: None,
            }) if id == "custom"
                && name == "Custom"
        );

        let provider = identity_providers.pop();
        assert_matches!(
            provider,
            Some(IdentityProvider {
                id,
                name,
                icon: Some(icon),
                brand: Some(IdentityProviderBrand::GitLab),
            }) if id == "oidc-gitlab"
                && name == "GitLab"
                && icon == "mxc://localhost/gitlab-icon"
        );
    }

    #[test]
    fn serialize_sso_login_type() {
        let wrapper = to_json_value(Wrapper {
            flows: vec![
                LoginType::Token(TokenLoginType {}),
                LoginType::Sso(SsoLoginType {
                    identity_providers: vec![IdentityProvider {
                        id: "oidc-github".into(),
                        name: "GitHub".into(),
                        icon: Some("mxc://localhost/github-icon".into()),
                        brand: Some(IdentityProviderBrand::GitHub),
                    }],
                }),
            ],
        })
        .unwrap();

        assert_eq!(
            wrapper,
            json!({
                "flows": [
                    {
                        "type": "m.login.token"
                    },
                    {
                        "type": "m.login.sso",
                        "identity_providers": [
                            {
                                "id": "oidc-github",
                                "name": "GitHub",
                                "icon": "mxc://localhost/github-icon",
                                "brand": "org.matrix.github"
                            },
                        ]
                    }
                ],
            })
        );
    }
}
<commit_msg>client-api: Update get_login_types tests<commit_after>//! [GET /_matrix/client/r0/login](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-login)

use std::borrow::Cow;

use ruma_api::ruma_api;
use ruma_identifiers::MxcUri;
use ruma_serde::{JsonObject, StringEnum};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::Value as JsonValue;

use crate::PrivOwnedStr;

ruma_api! {
    metadata: {
        description: "Gets the homeserver's supported login types to authenticate users. Clients should pick one of these and supply it as the type when logging in.",
        method: GET,
        name: "get_login_types",
        path: "/_matrix/client/r0/login",
        rate_limited: true,
        authentication: None,
    }

    #[derive(Default)]
    request: {}

    response: {
        /// The homeserver's supported login types.
        pub flows: Vec<LoginType>,
    }

    error: crate::Error
}

impl Request {
    /// Creates an empty `Request`.
    pub fn new() -> Self {
        Self {}
    }
}

impl Response {
    /// Creates a new `Response` with the given login types.
    pub fn new(flows: Vec<LoginType>) -> Self {
        Self { flows }
    }
}

/// An authentication mechanism.
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(untagged)]
pub enum LoginType {
    /// A password is supplied to authenticate.
    Password(PasswordLoginType),

    /// Token-based login.
    Token(TokenLoginType),

    /// SSO-based login.
    Sso(SsoLoginType),

    /// Custom login type.
    #[doc(hidden)]
    _Custom(CustomLoginType),
}

impl LoginType {
    /// Creates a new `LoginType` with the given `login_type` string and data.
    ///
    /// Prefer to use the public variants of `LoginType` where possible; this constructor is meant
    /// be used for unsupported login types only and does not allow setting arbitrary data for
    /// supported ones.
    pub fn new(login_type: &str, data: JsonObject) -> serde_json::Result<Self> {
        fn from_json_object<T: DeserializeOwned>(obj: JsonObject) -> serde_json::Result<T> {
            serde_json::from_value(JsonValue::Object(obj))
        }

        Ok(match login_type {
            "m.login.password" => Self::Password(from_json_object(data)?),
            "m.login.token" => Self::Token(from_json_object(data)?),
            "m.login.sso" => Self::Sso(from_json_object(data)?),
            _ => Self::_Custom(CustomLoginType { type_: login_type.to_owned(), data }),
        })
    }

    /// Returns a reference to the `login_type` string.
    pub fn login_type(&self) -> &str {
        match self {
            Self::Password(_) => "m.login.password",
            Self::Token(_) => "m.login.token",
            Self::Sso(_) => "m.login.sso",
            Self::_Custom(c) => &c.type_,
        }
    }

    /// Returns the associated data.
    ///
    /// Prefer to use the public variants of `LoginType` where possible; this method is meant to
    /// be used for unsupported login types only.
    pub fn data(&self) -> Cow<'_, JsonObject> {
        fn serialize<T: Serialize>(obj: &T) -> JsonObject {
            match serde_json::to_value(obj).expect("login type serialization to succeed") {
                JsonValue::Object(obj) => obj,
                _ => panic!("all login types must serialize to objects"),
            }
        }

        match self {
            Self::Password(d) => Cow::Owned(serialize(d)),
            Self::Token(d) => Cow::Owned(serialize(d)),
            Self::Sso(d) => Cow::Owned(serialize(d)),
            Self::_Custom(c) => Cow::Borrowed(&c.data),
        }
    }
}

/// The payload for password login.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type", rename = "m.login.password")]
pub struct PasswordLoginType {}

impl PasswordLoginType {
    /// Creates a new `PasswordLoginType`.
    pub fn new() -> Self {
        Self {}
    }
}

/// The payload for token-based login.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type", rename = "m.login.token")]
pub struct TokenLoginType {}

impl TokenLoginType {
    /// Creates a new `PasswordLoginType`.
    pub fn new() -> Self {
        Self {}
    }
}

/// The payload for SSO login.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type", rename = "m.login.sso")]
pub struct SsoLoginType {
    /// The identity provider choices.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub identity_providers: Vec<IdentityProvider>,
}

impl SsoLoginType {
    /// Creates a new `PasswordLoginType`.
    pub fn new() -> Self {
        Self::default()
    }
}

/// An SSO login identity provider.
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct IdentityProvider {
    /// The ID of the provider.
    pub id: String,

    /// The display name of the provider.
    pub name: String,

    /// The icon for the provider.
    pub icon: Option<Box<MxcUri>>,

    /// The brand identifier for the provider.
    pub brand: Option<IdentityProviderBrand>,
}

impl IdentityProvider {
    /// Creates an `IdentityProvider` with the given `id` and `name`.
    pub fn new(id: String, name: String) -> Self {
        Self { id, name, icon: None, brand: None }
    }
}

/// An SSO login identity provider brand identifier.
///
/// The predefined ones can be found in the matrix-doc repo in a [separate document][matrix-doc].
/// To use a custom brand string, simply use `IdentityProviderBrand::from("custom-brand")` or
/// `"custom-brand".into()` (if the type is known from the surrounding context).
///
/// [matrix-doc]: https://github.com/matrix-org/matrix-doc/blob/v1.1/informal/idp-brands.md
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum IdentityProviderBrand {
    /// The [Apple] brand.
    ///
    /// [Apple]: https://developer.apple.com/design/human-interface-guidelines/sign-in-with-apple/overview/buttons/
    #[ruma_enum(rename = "apple")]
    Apple,

    /// The [Facebook](https://developers.facebook.com/docs/facebook-login/web/login-button/) brand.
    #[ruma_enum(rename = "facebook")]
    Facebook,

    /// The [GitHub](https://github.com/logos) brand.
    #[ruma_enum(rename = "github")]
    GitHub,

    /// The [GitLab](https://about.gitlab.com/press/press-kit/) brand.
    #[ruma_enum(rename = "gitlab")]
    GitLab,

    /// The [Google](https://developers.google.com/identity/branding-guidelines) brand.
    #[ruma_enum(rename = "google")]
    Google,

    /// The [Twitter] brand.
    ///
    /// [Twitter]: https://developer.twitter.com/en/docs/authentication/guides/log-in-with-twitter#tab1
    #[ruma_enum(rename = "twitter")]
    Twitter,

    /// A custom brand.
    #[doc(hidden)]
    _Custom(PrivOwnedStr),
}

/// A custom login payload.
#[doc(hidden)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[allow(clippy::exhaustive_structs)]
pub struct CustomLoginType {
    /// A custom type
    ///
    /// This field is named `type_` instead of `type` because the latter is a reserved
    /// keyword in Rust.
    #[serde(rename = "type")]
    pub type_: String,

    /// Remaining type content
    #[serde(flatten)]
    pub data: JsonObject,
}

mod login_type_serde;

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    use serde::{Deserialize, Serialize};
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::{
        CustomLoginType, IdentityProvider, IdentityProviderBrand, LoginType, PasswordLoginType,
        SsoLoginType, TokenLoginType,
    };

    #[derive(Debug, Deserialize, Serialize)]
    struct Wrapper {
        pub flows: Vec<LoginType>,
    }

    #[test]
    fn deserialize_password_login_type() {
        assert_matches!(
            from_json_value::<Wrapper>(json!({
                "flows": [
                    { "type": "m.login.password" }
                ],
            })),
            Ok(Wrapper { flows })
            if flows.len() == 1
                && matches!(flows[0], LoginType::Password(PasswordLoginType {}))
        );
    }

    #[test]
    fn deserialize_custom_login_type() {
        assert_matches!(
            from_json_value::<Wrapper>(json!({
                "flows": [
                    {
                        "type": "io.ruma.custom",
                        "color": "green",
                    }
                ],
            })),
            Ok(Wrapper { flows })
            if flows.len() == 1
                && matches!(
                    &flows[0],
                    LoginType::_Custom(CustomLoginType { type_, data })
                        if type_ == "io.ruma.custom"
                        && data == json!({ "color": "green" }).as_object().unwrap()
                )
        );
    }

    #[test]
    fn deserialize_sso_login_type() {
        let mut wrapper = from_json_value::<Wrapper>(json!({
            "flows": [
                {
                    "type": "m.login.sso",
                    "identity_providers": [
                        {
                            "id": "oidc-gitlab",
                            "name": "GitLab",
                            "icon": "mxc://localhost/gitlab-icon",
                            "brand": "gitlab"
                        },
                        {
                            "id": "custom",
                            "name": "Custom",
                        }
                    ]
                }
            ],
        }))
        .unwrap();

        let flow = wrapper.flows.pop();
        assert_matches!(wrapper.flows.as_slice(), []);

        let mut identity_providers = match flow {
            Some(LoginType::Sso(SsoLoginType { identity_providers })) => identity_providers,
            _ => panic!("unexpected enum variant: {:?}", flow),
        };

        let provider = identity_providers.pop();
        assert_matches!(
            provider,
            Some(IdentityProvider {
                id,
                name,
                icon: None,
                brand: None,
            }) if id == "custom"
                && name == "Custom"
        );

        let provider = identity_providers.pop();
        assert_matches!(
            provider,
            Some(IdentityProvider {
                id,
                name,
                icon: Some(icon),
                brand: Some(IdentityProviderBrand::GitLab),
            }) if id == "oidc-gitlab"
                && name == "GitLab"
                && icon == "mxc://localhost/gitlab-icon"
        );
    }

    #[test]
    fn serialize_sso_login_type() {
        let wrapper = to_json_value(Wrapper {
            flows: vec![
                LoginType::Token(TokenLoginType {}),
                LoginType::Sso(SsoLoginType {
                    identity_providers: vec![IdentityProvider {
                        id: "oidc-github".into(),
                        name: "GitHub".into(),
                        icon: Some("mxc://localhost/github-icon".into()),
                        brand: Some(IdentityProviderBrand::GitHub),
                    }],
                }),
            ],
        })
        .unwrap();

        assert_eq!(
            wrapper,
            json!({
                "flows": [
                    {
                        "type": "m.login.token"
                    },
                    {
                        "type": "m.login.sso",
                        "identity_providers": [
                            {
                                "id": "oidc-github",
                                "name": "GitHub",
                                "icon": "mxc://localhost/github-icon",
                                "brand": "github"
                            },
                        ]
                    }
                ],
            })
        );
    }
}
<|endoftext|>


<commit_before>use std::io;
use super::{Deserialize, Serialize, Error, VarUint32, CountedList, InitExpr, CountedListWriter};

/// Entry in the element section.
#[derive(Debug, Clone)]
pub struct ElementSegment {
	index: u32,
	offset: InitExpr,
	members: Vec<u32>,
}

impl ElementSegment {
	/// New element segment.
	pub fn new(index: u32, offset: InitExpr, members: Vec<u32>) -> Self {
		ElementSegment { index: index, offset: offset, members: members }
	}

	/// Sequence of function indices.
	pub fn members(&self) -> &[u32] { &self.members }

	/// Sequence of function indices (mutable)
	pub fn members_mut(&mut self) -> &mut Vec<u32> { &mut self.members }

	/// Table index (currently valid only value of `0`)
	pub fn index(&self) -> u32 { self.index }

	/// An i32 initializer expression that computes the offset at which to place the elements.
	pub fn offset(&self) -> &InitExpr { &self.offset }

	/// An i32 initializer expression that computes the offset at which to place the elements (mutable)
	pub fn offset_mut(&mut self) -> &mut InitExpr { &mut self.offset }
}

impl Deserialize for ElementSegment {
	 type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let index = VarUint32::deserialize(reader)?;
		let offset = InitExpr::deserialize(reader)?;
		let funcs: Vec<u32> = CountedList::<VarUint32>::deserialize(reader)?
			.into_inner()
			.into_iter()
			.map(Into::into)
			.collect();

		Ok(ElementSegment {
			index: index.into(),
			offset: offset,
			members: funcs,
		})
	}
}

impl Serialize for ElementSegment {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		VarUint32::from(self.index).serialize(writer)?;
		self.offset.serialize(writer)?;
		let data = self.members;
		let counted_list = CountedListWriter::<VarUint32, _>(
			data.len(),
			data.into_iter().map(Into::into),
		);
		counted_list.serialize(writer)?;
		Ok(())
	}
}

/// Data segment definition.
#[derive(Clone, Debug)]
pub struct DataSegment {
	index: u32,
	offset: InitExpr,
	value: Vec<u8>,
}

impl DataSegment {
	/// New data segments.
	pub fn new(index: u32, offset: InitExpr, value: Vec<u8>) -> Self {
		DataSegment {
			index: index,
			offset: offset,
			value: value,
		}
	}

	/// Linear memory index (currently the only valid value is `0`).
	pub fn index(&self) -> u32 { self.index }

	/// An i32 initializer expression that computes the offset at which to place the data.
	pub fn offset(&self) -> &InitExpr { &self.offset }

	/// An i32 initializer expression that computes the offset at which to place the data (mutable)
	pub fn offset_mut(&mut self) -> &mut InitExpr { &mut self.offset }

	/// Initial value of the data segment.
	pub fn value(&self) -> &[u8] { &self.value }

	/// Initial value of the data segment (mutable).
	pub fn value_mut(&mut self) -> &mut Vec<u8> { &mut self.value }
}

impl Deserialize for DataSegment {
	 type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let index = VarUint32::deserialize(reader)?;
		let offset = InitExpr::deserialize(reader)?;
		let value_len = u32::from(VarUint32::deserialize(reader)?) as usize;

		let mut value_buf = Vec::new();
		let mut total_read = 0;
		let mut buf = [0u8; 65536];
		while total_read < value_len {
			let next_to_read = if value_len - total_read > 65536 { 65536 } else { value_len - total_read };
			reader.read_exact(&mut buf[0..next_to_read])?;
			value_buf.extend_from_slice(&buf[0..next_to_read]);
			total_read += next_to_read;
		}

		Ok(DataSegment {
			index: index.into(),
			offset: offset,
			value: value_buf,
		})
	}
}

impl Serialize for DataSegment {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		VarUint32::from(self.index).serialize(writer)?;
		self.offset.serialize(writer)?;

		let value = self.value;
		VarUint32::from(value.len()).serialize(writer)?;
		writer.write_all(&value[..])?;
		Ok(())
	}
}
<commit_msg>also segment via macro<commit_after>use std::io;
use super::{Deserialize, Serialize, Error, VarUint32, CountedList, InitExpr, CountedListWriter};

/// Entry in the element section.
#[derive(Debug, Clone)]
pub struct ElementSegment {
	index: u32,
	offset: InitExpr,
	members: Vec<u32>,
}

impl ElementSegment {
	/// New element segment.
	pub fn new(index: u32, offset: InitExpr, members: Vec<u32>) -> Self {
		ElementSegment { index: index, offset: offset, members: members }
	}

	/// Sequence of function indices.
	pub fn members(&self) -> &[u32] { &self.members }

	/// Sequence of function indices (mutable)
	pub fn members_mut(&mut self) -> &mut Vec<u32> { &mut self.members }

	/// Table index (currently valid only value of `0`)
	pub fn index(&self) -> u32 { self.index }

	/// An i32 initializer expression that computes the offset at which to place the elements.
	pub fn offset(&self) -> &InitExpr { &self.offset }

	/// An i32 initializer expression that computes the offset at which to place the elements (mutable)
	pub fn offset_mut(&mut self) -> &mut InitExpr { &mut self.offset }
}

impl Deserialize for ElementSegment {
	 type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let index = VarUint32::deserialize(reader)?;
		let offset = InitExpr::deserialize(reader)?;
		let funcs: Vec<u32> = CountedList::<VarUint32>::deserialize(reader)?
			.into_inner()
			.into_iter()
			.map(Into::into)
			.collect();

		Ok(ElementSegment {
			index: index.into(),
			offset: offset,
			members: funcs,
		})
	}
}

impl Serialize for ElementSegment {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		VarUint32::from(self.index).serialize(writer)?;
		self.offset.serialize(writer)?;
		let data = self.members;
		let counted_list = CountedListWriter::<VarUint32, _>(
			data.len(),
			data.into_iter().map(Into::into),
		);
		counted_list.serialize(writer)?;
		Ok(())
	}
}

/// Data segment definition.
#[derive(Clone, Debug)]
pub struct DataSegment {
	index: u32,
	offset: InitExpr,
	value: Vec<u8>,
}

impl DataSegment {
	/// New data segments.
	pub fn new(index: u32, offset: InitExpr, value: Vec<u8>) -> Self {
		DataSegment {
			index: index,
			offset: offset,
			value: value,
		}
	}

	/// Linear memory index (currently the only valid value is `0`).
	pub fn index(&self) -> u32 { self.index }

	/// An i32 initializer expression that computes the offset at which to place the data.
	pub fn offset(&self) -> &InitExpr { &self.offset }

	/// An i32 initializer expression that computes the offset at which to place the data (mutable)
	pub fn offset_mut(&mut self) -> &mut InitExpr { &mut self.offset }

	/// Initial value of the data segment.
	pub fn value(&self) -> &[u8] { &self.value }

	/// Initial value of the data segment (mutable).
	pub fn value_mut(&mut self) -> &mut Vec<u8> { &mut self.value }
}

impl Deserialize for DataSegment {
	 type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let index = VarUint32::deserialize(reader)?;
		let offset = InitExpr::deserialize(reader)?;
		let value_len = u32::from(VarUint32::deserialize(reader)?) as usize;
		let value_buf = buffered_read!(65546, value_len, reader);

		Ok(DataSegment {
			index: index.into(),
			offset: offset,
			value: value_buf,
		})
	}
}

impl Serialize for DataSegment {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		VarUint32::from(self.index).serialize(writer)?;
		self.offset.serialize(writer)?;

		let value = self.value;
		VarUint32::from(value.len()).serialize(writer)?;
		writer.write_all(&value[..])?;
		Ok(())
	}
}
<|endoftext|>


<commit_before>//! This module defines Concrete Syntax Tree (CST), used by rust-analyzer.
//!
//! The CST includes comments and whitespace, provides a single node type,
//! `SyntaxNode`, and a basic traversal API (parent, children, siblings).
//!
//! The *real* implementation is in the (language-agnostic) `rowan` crate, this
//! module just wraps its API.

use rowan::{GreenNodeBuilder, Language};

use crate::{Parse, SmolStr, SyntaxError, SyntaxKind, TextSize};

pub(crate) use rowan::{GreenNode, GreenToken};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum RustLanguage {}
impl Language for RustLanguage {
    type Kind = SyntaxKind;

    fn kind_from_raw(raw: rowan::SyntaxKind) -> SyntaxKind {
        SyntaxKind::from(raw.0)
    }

    fn kind_to_raw(kind: SyntaxKind) -> rowan::SyntaxKind {
        rowan::SyntaxKind(kind.into())
    }
}

pub type SyntaxNode = rowan::SyntaxNode<RustLanguage>;
pub type SyntaxToken = rowan::SyntaxToken<RustLanguage>;
pub type SyntaxElement = rowan::SyntaxElement<RustLanguage>;
pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren<RustLanguage>;
pub type SyntaxElementChildren = rowan::SyntaxElementChildren<RustLanguage>;

pub use rowan::{Direction, NodeOrToken};

#[derive(Default)]
pub struct SyntaxTreeBuilder {
    errors: Vec<SyntaxError>,
    inner: GreenNodeBuilder<'static>,
}

impl SyntaxTreeBuilder {
    pub(crate) fn finish_raw(self) -> (GreenNode, Vec<SyntaxError>) {
        let green = self.inner.finish();
        (green, self.errors)
    }

    pub fn finish(self) -> Parse<SyntaxNode> {
        let (green, errors) = self.finish_raw();
        let node = SyntaxNode::new_root(green);
        if cfg!(debug_assertions) {
            crate::validation::validate_block_structure(&node);
        }
        Parse::new(node.green().clone(), errors)
    }

    pub fn token(&mut self, kind: SyntaxKind, text: SmolStr) {
        let kind = RustLanguage::kind_to_raw(kind);
        self.inner.token(kind, text)
    }

    pub fn start_node(&mut self, kind: SyntaxKind) {
        let kind = RustLanguage::kind_to_raw(kind);
        self.inner.start_node(kind)
    }

    pub fn finish_node(&mut self) {
        self.inner.finish_node()
    }

    pub fn error(&mut self, error: ra_parser::ParseError, text_pos: TextSize) {
        self.errors.push(SyntaxError::new_at_offset(*error.0, text_pos))
    }
}
<commit_msg>Small refactor<commit_after>//! This module defines Concrete Syntax Tree (CST), used by rust-analyzer.
//!
//! The CST includes comments and whitespace, provides a single node type,
//! `SyntaxNode`, and a basic traversal API (parent, children, siblings).
//!
//! The *real* implementation is in the (language-agnostic) `rowan` crate, this
//! module just wraps its API.

use rowan::{GreenNodeBuilder, Language};

use crate::{Parse, SmolStr, SyntaxError, SyntaxKind, TextSize};

pub(crate) use rowan::{GreenNode, GreenToken};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum RustLanguage {}
impl Language for RustLanguage {
    type Kind = SyntaxKind;

    fn kind_from_raw(raw: rowan::SyntaxKind) -> SyntaxKind {
        SyntaxKind::from(raw.0)
    }

    fn kind_to_raw(kind: SyntaxKind) -> rowan::SyntaxKind {
        rowan::SyntaxKind(kind.into())
    }
}

pub type SyntaxNode = rowan::SyntaxNode<RustLanguage>;
pub type SyntaxToken = rowan::SyntaxToken<RustLanguage>;
pub type SyntaxElement = rowan::SyntaxElement<RustLanguage>;
pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren<RustLanguage>;
pub type SyntaxElementChildren = rowan::SyntaxElementChildren<RustLanguage>;

pub use rowan::{Direction, NodeOrToken};

#[derive(Default)]
pub struct SyntaxTreeBuilder {
    errors: Vec<SyntaxError>,
    inner: GreenNodeBuilder<'static>,
}

impl SyntaxTreeBuilder {
    pub(crate) fn finish_raw(self) -> (GreenNode, Vec<SyntaxError>) {
        let green = self.inner.finish();
        (green, self.errors)
    }

    pub fn finish(self) -> Parse<SyntaxNode> {
        let (green, errors) = self.finish_raw();
        if cfg!(debug_assertions) {
            let node = SyntaxNode::new_root(green.clone());
            crate::validation::validate_block_structure(&node);
        }
        Parse::new(green, errors)
    }

    pub fn token(&mut self, kind: SyntaxKind, text: SmolStr) {
        let kind = RustLanguage::kind_to_raw(kind);
        self.inner.token(kind, text)
    }

    pub fn start_node(&mut self, kind: SyntaxKind) {
        let kind = RustLanguage::kind_to_raw(kind);
        self.inner.start_node(kind)
    }

    pub fn finish_node(&mut self) {
        self.inner.finish_node()
    }

    pub fn error(&mut self, error: ra_parser::ParseError, text_pos: TextSize) {
        self.errors.push(SyntaxError::new_at_offset(*error.0, text_pos))
    }
}
<|endoftext|>


<commit_before>use std::io::Read;

use common::Solution;
use common::read_single_input;

fn skill_after(n: usize) -> u64 {
    let mut state = vec![3u8, 7];
    let mut elves = [0, 1];

    while state.len() < n + 10 {
        let result = state[elves[0]] + state[elves[1]];
        if result >= 10 {
            state.push(result / 10);
        }
        state.push(result % 10);

        elves[0] = (elves[0] + state[elves[0]] as usize + 1) % state.len();
        elves[1] = (elves[1] + state[elves[1]] as usize + 1) % state.len();
    }

    let mut skill = 0;
    for d in state.into_iter().skip(n).take(10) {
        skill *= 10;
        skill += d as u64;
    }

    skill
}

fn update_current(mut current: usize, by: usize, base: usize) -> usize {
    current *= 10;
    current %= base;
    current += by;
    current
}

fn find_first(n: usize, len: usize) -> usize {
    let mut state = vec![3u8, 7];
    let mut elves = [0, 1];
    let mut current = 37;
    let mod_base = 10usize.pow(len as u32);

    loop {
        let result = state[elves[0]] + state[elves[1]];
        if result >= 10 {
            current = update_current(current, result as usize / 10, mod_base);
            if current == n {
                return state.len() - 5;
            }
            state.push(result / 10);
        }
        current = update_current(current, result as usize % 10, mod_base);
        if current == n {
            return state.len() - 5 + 1;
        }
        state.push(result % 10);

        elves[0] = (elves[0] + state[elves[0]] as usize + 1) % state.len();
        elves[1] = (elves[1] + state[elves[1]] as usize + 1) % state.len();
    }
}

#[derive(Default)]
pub struct Day14 {}

impl Day14 {
    pub fn new() -> Self {
        Default::default()
    }
}

impl Solution for Day14 {
    fn part1(&mut self, input: &mut Read) -> String {
        let input = read_single_input(input);
        format!("{:010}", skill_after(input))
    }

    fn part2(&mut self, input: &mut Read) -> String {
        let mut buf = String::new();
        input.read_to_string(&mut buf).unwrap();

        let input = buf.trim().parse().unwrap();
        format!("{}", find_first(input, buf.trim().len()))
    }
}

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

    #[test]
    fn test_skill_after() {
        assert_eq!(5158916779, skill_after(9));
        assert_eq!(124515891, skill_after(5));
        assert_eq!(9251071085, skill_after(18));
        assert_eq!(5941429882, skill_after(2018));
    }

    #[test]
    fn test_find_first() {
        assert_eq!(9, find_first(51589, 5));
        assert_eq!(5, find_first(1245, 5));
        assert_eq!(18, find_first(92510, 5));
        assert_eq!(2018, find_first(59414, 5));
    }
}
<commit_msg>Off-by-one bug fix<commit_after>use std::io::Read;

use common::Solution;
use common::read_single_input;

fn skill_after(n: usize) -> u64 {
    let mut state = vec![3u8, 7];
    let mut elves = [0, 1];

    while state.len() < n + 10 {
        let result = state[elves[0]] + state[elves[1]];
        if result >= 10 {
            state.push(result / 10);
        }
        state.push(result % 10);

        elves[0] = (elves[0] + state[elves[0]] as usize + 1) % state.len();
        elves[1] = (elves[1] + state[elves[1]] as usize + 1) % state.len();
    }

    let mut skill = 0;
    for d in state.into_iter().skip(n).take(10) {
        skill *= 10;
        skill += d as u64;
    }

    skill
}

fn update_current(mut current: usize, by: usize, base: usize) -> usize {
    current *= 10;
    current %= base;
    current += by;
    current
}

fn find_first(n: usize, len: usize) -> usize {
    let mut state = vec![3u8, 7];
    let mut elves = [0, 1];
    let mut current = 37;
    let mod_base = 10usize.pow(len as u32);

    loop {
        let result = state[elves[0]] + state[elves[1]];
        if result >= 10 {
            current = update_current(current, result as usize / 10, mod_base);
            if current == n {
                return state.len() - len + 1;
            }
            state.push(result / 10);
        }
        current = update_current(current, result as usize % 10, mod_base);
        if current == n {
            return state.len() - len + 1;
        }
        state.push(result % 10);

        elves[0] = (elves[0] + state[elves[0]] as usize + 1) % state.len();
        elves[1] = (elves[1] + state[elves[1]] as usize + 1) % state.len();
    }
}

#[derive(Default)]
pub struct Day14 {}

impl Day14 {
    pub fn new() -> Self {
        Default::default()
    }
}

impl Solution for Day14 {
    fn part1(&mut self, input: &mut Read) -> String {
        let input = read_single_input(input);
        format!("{:010}", skill_after(input))
    }

    fn part2(&mut self, input: &mut Read) -> String {
        let mut buf = String::new();
        input.read_to_string(&mut buf).unwrap();

        let input = buf.trim().parse().unwrap();
        format!("{}", find_first(input, buf.trim().len()))
    }
}

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

    #[test]
    fn test_skill_after() {
        assert_eq!(5158916779, skill_after(9));
        assert_eq!(124515891, skill_after(5));
        assert_eq!(9251071085, skill_after(18));
        assert_eq!(5941429882, skill_after(2018));
    }

    #[test]
    fn test_find_first() {
        assert_eq!(9, find_first(51589, 5));
        assert_eq!(5, find_first(1245, 5));
        assert_eq!(18, find_first(92510, 5));
        assert_eq!(2018, find_first(59414, 5));
    }
}
<|endoftext|>


<commit_before>//! System operations instructions

use utils::address::Address;
use utils::bigint::{U256, M256};
use utils::gas::Gas;
use vm::{Memory, Log, Context, Transaction};
use super::State;

use std::cmp::min;
use tiny_keccak::Keccak;
use vm::eval::utils::copy_from_memory;

pub fn suicide<M: Memory + Default>(state: &mut State<M>) {
    pop!(state, address: Address);
    let balance = state.account_state.balance(state.context.address).unwrap();
    state.account_state.increase_balance(address, balance);
    state.account_state.remove(state.context.address).unwrap();
    state.removed.push(address);
}

pub fn log<M: Memory + Default>(state: &mut State<M>, topic_len: usize) {
    pop!(state, index, len);
    let data = copy_from_memory(&state.memory, index, len);
    let mut topics = Vec::new();
    for _ in 0..topic_len {
        topics.push(state.stack.pop().unwrap());
    }

    state.logs.push(Log {
        address: state.context.address,
        data: data,
        topics: topics,
    });
}

pub fn sha3<M: Memory + Default>(state: &mut State<M>) {
    pop!(state, from, len);
    let data = copy_from_memory(&state.memory, from, len);
    let mut sha3 = Keccak::new_keccak256();
    sha3.update(data.as_slice());
    let mut ret = [0u8; 32];
    sha3.finalize(&mut ret);
    push!(state, M256::from(ret.as_ref()));
}

pub fn create<M: Memory + Default>(state: &mut State<M>, after_gas: Gas) -> Option<Context> {
    pop!(state, value: U256);
    pop!(state, init_start, init_len);
    if state.account_state.balance(state.context.address).unwrap() < value {
        push!(state, M256::zero());
        return None;
    }

    let init = copy_from_memory(&state.memory, init_start, init_len);
    let transaction = Transaction::ContractCreation {
        caller: state.context.address,
        gas_price: state.context.gas_price,
        gas_limit: after_gas,
        value: value,
        init: init,
    };
    let context = transaction.into_context(
        Gas::zero(), Some(state.context.origin), &mut state.account_state, true
    ).unwrap();

    state.account_state.mark_exists(context.address).unwrap();

    push!(state, context.address.into());
    Some(context)
}

pub fn call<M: Memory + Default>(state: &mut State<M>, stipend_gas: Gas, after_gas: Gas, as_self: bool) -> Option<(Context, (M256, M256))> {
    pop!(state, gas: Gas, to: Address, value: U256);
    pop!(state, in_start, in_len, out_start, out_len);
    if state.account_state.balance(state.context.address).unwrap() < value {
        push!(state, M256::zero());
        return None;
    }

    let input = copy_from_memory(&state.memory, in_start, in_len);
    let gas_limit = min(gas + stipend_gas, after_gas);

    let transaction = Transaction::MessageCall {
        address: to,
        caller: state.context.address,
        gas_price: state.context.gas_price,
        gas_limit: gas_limit,
        value: value,
        data: input,
    };

    let mut context = transaction.into_context(
        Gas::zero(), Some(state.context.origin), &mut state.account_state, true
    ).unwrap();
    if as_self {
        context.address = state.context.address;
    }

    state.account_state.mark_exists(context.address).unwrap();

    push!(state, M256::from(1u64));
    Some((context, (out_start, out_len)))
}
<commit_msg>Problem: no need to mark exists for CREATE<commit_after>//! System operations instructions

use utils::address::Address;
use utils::bigint::{U256, M256};
use utils::gas::Gas;
use vm::{Memory, Log, Context, Transaction};
use super::State;

use std::cmp::min;
use tiny_keccak::Keccak;
use vm::eval::utils::copy_from_memory;

pub fn suicide<M: Memory + Default>(state: &mut State<M>) {
    pop!(state, address: Address);
    let balance = state.account_state.balance(state.context.address).unwrap();
    state.account_state.increase_balance(address, balance);
    state.account_state.remove(state.context.address).unwrap();
    state.removed.push(address);
}

pub fn log<M: Memory + Default>(state: &mut State<M>, topic_len: usize) {
    pop!(state, index, len);
    let data = copy_from_memory(&state.memory, index, len);
    let mut topics = Vec::new();
    for _ in 0..topic_len {
        topics.push(state.stack.pop().unwrap());
    }

    state.logs.push(Log {
        address: state.context.address,
        data: data,
        topics: topics,
    });
}

pub fn sha3<M: Memory + Default>(state: &mut State<M>) {
    pop!(state, from, len);
    let data = copy_from_memory(&state.memory, from, len);
    let mut sha3 = Keccak::new_keccak256();
    sha3.update(data.as_slice());
    let mut ret = [0u8; 32];
    sha3.finalize(&mut ret);
    push!(state, M256::from(ret.as_ref()));
}

pub fn create<M: Memory + Default>(state: &mut State<M>, after_gas: Gas) -> Option<Context> {
    pop!(state, value: U256);
    pop!(state, init_start, init_len);
    if state.account_state.balance(state.context.address).unwrap() < value {
        push!(state, M256::zero());
        return None;
    }

    let init = copy_from_memory(&state.memory, init_start, init_len);
    let transaction = Transaction::ContractCreation {
        caller: state.context.address,
        gas_price: state.context.gas_price,
        gas_limit: after_gas,
        value: value,
        init: init,
    };
    let context = transaction.into_context(
        Gas::zero(), Some(state.context.origin), &mut state.account_state, true
    ).unwrap();

    push!(state, context.address.into());
    Some(context)
}

pub fn call<M: Memory + Default>(state: &mut State<M>, stipend_gas: Gas, after_gas: Gas, as_self: bool) -> Option<(Context, (M256, M256))> {
    pop!(state, gas: Gas, to: Address, value: U256);
    pop!(state, in_start, in_len, out_start, out_len);
    if state.account_state.balance(state.context.address).unwrap() < value {
        push!(state, M256::zero());
        return None;
    }

    let input = copy_from_memory(&state.memory, in_start, in_len);
    let gas_limit = min(gas + stipend_gas, after_gas);

    let transaction = Transaction::MessageCall {
        address: to,
        caller: state.context.address,
        gas_price: state.context.gas_price,
        gas_limit: gas_limit,
        value: value,
        data: input,
    };

    let mut context = transaction.into_context(
        Gas::zero(), Some(state.context.origin), &mut state.account_state, true
    ).unwrap();
    if as_self {
        context.address = state.context.address;
    }

    state.account_state.mark_exists(context.address).unwrap();

    push!(state, M256::from(1u64));
    Some((context, (out_start, out_len)))
}
<|endoftext|>